LibreOffice Module ucb (master) 1
webdavresponseparser.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
22#include "DAVProperties.hxx"
24
27
29#include <com/sun/star/xml/sax/Parser.hpp>
30#include <com/sun/star/xml/sax/InputSource.hpp>
31#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
32#include <com/sun/star/ucb/LockEntry.hpp>
33#include <com/sun/star/ucb/LockScope.hpp>
34#include <com/sun/star/ucb/LockType.hpp>
35#include <com/sun/star/ucb/Lock.hpp>
36#include <map>
37#include <unordered_map>
38#include <rtl/ref.hxx>
39#include <rtl/uri.hxx>
40#include <sal/log.hxx>
41#include <o3tl/string_view.hxx>
42
43using namespace com::sun::star;
44using namespace http_dav_ucp;
45
46
47// WebDAVNamespace enum and StringToEnum converter
48namespace
49{
50 enum WebDAVNamespace
51 {
52 WebDAVNamespace_unknown = 0,
53 WebDAVNamespace_DAV,
54 WebDAVNamespace_ucb_openoffice_org_dav_props,
55
56 WebDAVNamespace_last
57 };
58
59 WebDAVNamespace StrToWebDAVNamespace(::std::u16string_view rStr)
60 {
61 if (rStr == u"DAV:")
62 {
63 return WebDAVNamespace_DAV;
64 }
65 else if (rStr == u"http://ucb.openoffice.org/dav/props/")
66 {
67 return WebDAVNamespace_ucb_openoffice_org_dav_props;
68 }
69
70 return WebDAVNamespace_unknown;
71 }
72} // end of anonymous namespace
73
74// WebDAVName enum and StringToEnum converter using unordered_map
75namespace
76{
77 enum WebDAVName
78 {
79 WebDAVName_unknown = 0,
80 WebDAVName_activelock,
81 WebDAVName_lockdiscovery,
82 WebDAVName_multistatus,
83 WebDAVName_response,
84 WebDAVName_href,
85 WebDAVName_propstat,
86 WebDAVName_prop,
87 WebDAVName_resourcetype,
88 WebDAVName_collection,
89 WebDAVName_getcontenttype,
90 WebDAVName_supportedlock,
91 WebDAVName_lockentry,
92 WebDAVName_lockscope,
93 WebDAVName_depth,
94 WebDAVName_locktoken,
95 WebDAVName_exclusive,
96 WebDAVName_locktype,
97 WebDAVName_owner,
98 WebDAVName_timeout,
99 WebDAVName_write,
100 WebDAVName_shared,
101 WebDAVName_status,
102 WebDAVName_getlastmodified,
103 WebDAVName_creationdate,
104 WebDAVName_getcontentlength,
105 WebDAVName_type,
106 WebDAVName_value,
107 WebDAVName_ucbprop,
108
109 WebDAVName_last
110 };
111
112 WebDAVName StrToWebDAVName(const OUString& rStr)
113 {
114 typedef std::unordered_map< OUString, WebDAVName > WebDAVNameMapper;
115 typedef std::pair< OUString, WebDAVName > WebDAVNameValueType;
116 static WebDAVNameMapper aWebDAVNameMapperList;
117
118 if(aWebDAVNameMapperList.empty())
119 {
120 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("activelock"), WebDAVName_activelock));
121 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("lockdiscovery"), WebDAVName_lockdiscovery));
122 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("multistatus"), WebDAVName_multistatus));
123 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("response"), WebDAVName_response));
124 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("href"), WebDAVName_href));
125 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("propstat"), WebDAVName_propstat));
126 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("prop"), WebDAVName_prop));
127 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("resourcetype"), WebDAVName_resourcetype));
128 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("collection"), WebDAVName_collection));
129 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("getcontenttype"), WebDAVName_getcontenttype));
130 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("supportedlock"), WebDAVName_supportedlock));
131 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("lockentry"), WebDAVName_lockentry));
132 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("lockscope"), WebDAVName_lockscope));
133 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("depth"), WebDAVName_depth));
134 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("locktoken"), WebDAVName_locktoken));
135 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("exclusive"), WebDAVName_exclusive));
136 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("locktype"), WebDAVName_locktype));
137 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("owner"), WebDAVName_owner));
138 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("timeout"), WebDAVName_timeout));
139 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("write"), WebDAVName_write));
140 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("shared"), WebDAVName_shared));
141 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("status"), WebDAVName_status));
142 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("getlastmodified"), WebDAVName_getlastmodified));
143 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("creationdate"), WebDAVName_creationdate));
144 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("getcontentlength"), WebDAVName_getcontentlength));
145 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("type"), WebDAVName_type));
146 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("value"), WebDAVName_value));
147 aWebDAVNameMapperList.insert(WebDAVNameValueType(OUString("ucbprop"), WebDAVName_ucbprop));
148 }
149
150 const WebDAVNameMapper::const_iterator aResult(aWebDAVNameMapperList.find(rStr));
151
152 if(aResult == aWebDAVNameMapperList.end())
153 {
154 return WebDAVName_unknown;
155 }
156 else
157 {
158 return aResult->second;
159 }
160 }
161} // end of anonymous namespace
162
163
164// WebDAVContext, holding information for each start/endElement pair
165
166namespace
167{
168 typedef std::map< OUString, OUString > NamespaceMap;
169
170 class WebDAVContext
171 {
172 private:
173 WebDAVContext* mpParent;
174 NamespaceMap maNamespaceMap;
175 OUString maWhiteSpace;
176
177 OUString maNamespace;
178 OUString maName;
179
180 WebDAVNamespace maWebDAVNamespace;
181 WebDAVName maWebDAVName;
182
183 // local helpers
184 void parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs);
185 OUString mapNamespaceToken(const OUString& rToken) const;
186 void splitName(const OUString& rSource);
187
188 public:
189 WebDAVContext(WebDAVContext* pParent, const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs);
190
191 WebDAVContext* getParent() const { return mpParent; }
192 OUString& getWhiteSpace() { return maWhiteSpace; }
193 void setWhiteSpace(const OUString& rNew) { maWhiteSpace = rNew; }
194
195 const OUString& getNamespace() const { return maNamespace; }
196 const OUString& getName() const { return maName; }
197 const WebDAVNamespace& getWebDAVNamespace() const { return maWebDAVNamespace; }
198 const WebDAVName& getWebDAVName() const { return maWebDAVName; }
199 };
200
201 void WebDAVContext::parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs)
202 {
203 const sal_Int16 nAttributes(xAttribs->getLength());
204
205 for(sal_Int16 a(0); a < nAttributes; a++)
206 {
207 const OUString aName(xAttribs->getNameByIndex(a));
208 const sal_Int32 nLen(aName.getLength());
209
210 if(nLen)
211 {
212 if(aName.startsWith("xmlns"))
213 {
214 const sal_Int32 nIndex(aName.indexOf(':', 0));
215
216 if(-1 != nIndex && nIndex + 1 < nLen)
217 {
218 const OUString aToken(aName.copy(nIndex + 1));
219
220 maNamespaceMap.emplace(aToken, xAttribs->getValueByIndex(a));
221 }
222 }
223 }
224 }
225 }
226
227 OUString WebDAVContext::mapNamespaceToken(const OUString& rToken) const
228 {
229 NamespaceMap::const_iterator iter = maNamespaceMap.find(rToken);
230
231 if(maNamespaceMap.end() == iter)
232 {
233 if(getParent())
234 {
235 return getParent()->mapNamespaceToken(rToken);
236 }
237 else
238 {
239 return rToken;
240 }
241 }
242 else
243 {
244 return (*iter).second;
245 }
246 }
247
248 void WebDAVContext::splitName(const OUString& rSource)
249 {
250 const sal_Int32 nLen(rSource.getLength());
251 maNamespace.clear();
252 maName = rSource;
253
254 if(nLen)
255 {
256 const sal_Int32 nIndex(rSource.indexOf(':', 0));
257
258 if(nIndex > 0 && ((nIndex + 1) < nLen))
259 {
260 maNamespace = mapNamespaceToken(rSource.copy(0, nIndex));
261 maName = rSource.copy(nIndex + 1);
262 }
263 }
264 }
265
266 WebDAVContext::WebDAVContext(WebDAVContext* pParent, const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs)
267 : mpParent(pParent),
268 maNamespaceMap(),
269 maWhiteSpace(),
270 maNamespace(),
271 maName(),
272 maWebDAVNamespace(WebDAVNamespace_unknown),
273 maWebDAVName(WebDAVName_unknown)
274 {
275 const sal_Int16 nAttributes(xAttribs->getLength());
276
277 if(nAttributes)
278 {
279 // parse evtl. namespace entries
280 parseForNamespaceTokens(xAttribs);
281 }
282
283 // split name to namespace and name
284 splitName(aName);
285
286 // evaluate enums for namespace and name
287 maWebDAVNamespace = StrToWebDAVNamespace(maNamespace);
288 maWebDAVName = StrToWebDAVName(maName);
289 }
290} // end of anonymous namespace
291
292
293// the Xml parser itself
294
295namespace
296{
297 enum WebDAVResponseParserMode
298 {
299 WebDAVResponseParserMode_PropFind = 0,
300 WebDAVResponseParserMode_PropName,
301 WebDAVResponseParserMode_Lock
302 };
303
304 class WebDAVResponseParser : public cppu::WeakImplHelper< css::xml::sax::XDocumentHandler >
305 {
306 private:
307 std::vector< ucb::Lock > maResult_Lock;
308 std::vector< http_dav_ucp::DAVResource > maResult_PropFind;
309 std::vector< http_dav_ucp::DAVResourceInfo > maResult_PropName;
310
311 WebDAVContext* mpContext;
312 OUString maHref;
313 OUString maStatus;
314 OUString m_UCBType;
315 OUString m_UCBValue;
316 std::vector< http_dav_ucp::DAVPropertyValue > maResponseProperties;
317 std::vector< http_dav_ucp::DAVPropertyValue > maPropStatProperties;
318 std::vector< OUString > maResponseNames;
319 std::vector< OUString > maPropStatNames;
320 uno::Sequence< ucb::LockEntry > maLockEntries;
321 ucb::LockScope maLockScope;
322 ucb::LockType maLockType;
323 ucb::Lock maLock;
324 WebDAVResponseParserMode meWebDAVResponseParserMode;
325
326 bool mbResourceTypeCollection : 1;
327 bool mbLockScopeSet : 1;
328 bool mbLockTypeSet : 1;
329
330 // local helpers
331 bool whitespaceIsAvailable() const
332 {
333 return mpContext && mpContext->getWhiteSpace().getLength();
334 }
335 bool hasParent(WebDAVName aWebDAVName) const
336 {
337 return mpContext && mpContext->getParent() && aWebDAVName == mpContext->getParent()->getWebDAVName();
338 }
339 bool propertyIsReady() const
340 {
341 return hasParent(WebDAVName_prop) && whitespaceIsAvailable();
342 }
343 bool isCollectingProperties() const
344 {
345 return WebDAVResponseParserMode_PropFind == meWebDAVResponseParserMode;
346 }
347 bool isCollectingPropNames() const
348 {
349 return WebDAVResponseParserMode_PropName == meWebDAVResponseParserMode;
350 }
351 bool collectThisPropertyAsName() const
352 {
353 return isCollectingPropNames() && hasParent(WebDAVName_prop);
354 }
355 void pop_context()
356 {
357 if(mpContext)
358 {
359 WebDAVContext* pTemp = mpContext;
360 mpContext = mpContext->getParent();
361 delete pTemp;
362 }
363 else
364 {
365 SAL_WARN( "ucb.ucp.webdav", "Parser context pop without context (!)");
366 }
367 }
368
369 public:
370 explicit WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode);
371 virtual ~WebDAVResponseParser() override;
372
373 // Methods XDocumentHandler
374 virtual void SAL_CALL startDocument( ) override;
375 virtual void SAL_CALL endDocument( ) override;
376 virtual void SAL_CALL startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) override;
377 virtual void SAL_CALL endElement( const OUString& aName ) override;
378 virtual void SAL_CALL characters( const OUString& aChars ) override;
379 virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override;
380 virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override;
381 virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) override;
382
383 const std::vector< ucb::Lock >& getResult_Lock() const { return maResult_Lock; }
384 const std::vector< http_dav_ucp::DAVResource >& getResult_PropFind() const { return maResult_PropFind; }
385 const std::vector< http_dav_ucp::DAVResourceInfo >& getResult_PropName() const { return maResult_PropName; }
386 };
387
388 WebDAVResponseParser::WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode)
389 : maResult_PropFind(),
390 maResult_PropName(),
391 mpContext(nullptr),
392 maHref(),
393 maStatus(),
394 maResponseProperties(),
395 maPropStatProperties(),
396 maResponseNames(),
397 maPropStatNames(),
398 maLockEntries(),
399 maLockScope(ucb::LockScope_EXCLUSIVE),
400 maLockType(ucb::LockType_WRITE),
401 meWebDAVResponseParserMode(eWebDAVResponseParserMode),
402 mbResourceTypeCollection(false),
403 mbLockScopeSet(false),
404 mbLockTypeSet(false)
405 {
406 }
407
408 WebDAVResponseParser::~WebDAVResponseParser()
409 {
410 SAL_WARN_IF(mpContext, "ucb.ucp.webdav", "Parser destructed with existing content (!)");
411 while(mpContext)
412 {
413 pop_context();
414 }
415 }
416
417 void SAL_CALL WebDAVResponseParser::startDocument( )
418 {
419 SAL_WARN_IF(mpContext, "ucb.ucp.webdav", "Parser start with existing content (!)");
420 }
421
422 void SAL_CALL WebDAVResponseParser::endDocument( )
423 {
424 SAL_WARN_IF(mpContext, "ucb.ucp.webdav", "Parser end with existing content (!)");
425 }
426
427 void SAL_CALL WebDAVResponseParser::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
428 {
429 const sal_Int32 nLen(aName.getLength());
430
431 if(nLen)
432 {
433 // create new context (push)
434 mpContext = new WebDAVContext(mpContext, aName, xAttribs);
435
436 if(collectThisPropertyAsName())
437 {
438 // When collecting property names and parent is prop there is no need
439 // to handle the content of this property deeper (evtl. preparations)
440 }
441 else
442 {
443 switch(mpContext->getWebDAVNamespace())
444 {
445 default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
446 {
447 break;
448 }
449 case WebDAVNamespace_DAV:
450 {
451 switch(mpContext->getWebDAVName())
452 {
453 default: // WebDAVName_unknown, WebDAVName_last or unhandled
454 {
455 break;
456 }
457 case WebDAVName_propstat:
458 {
459 // propstat start
460 if(isCollectingProperties())
461 {
462 // reset maPropStatProperties
463 maPropStatProperties.clear();
464 }
465 else
466 {
467 // when collecting properties reset maPropStatNames
468 maPropStatNames.clear();
469 }
470 break;
471 }
472 case WebDAVName_response:
473 {
474 // response start, reset Href and status and maResponseProperties
475 maHref.clear();
476 maStatus.clear();
477
478 if(isCollectingProperties())
479 {
480 // reset maResponseProperties
481 maResponseProperties.clear();
482 }
483 else
484 {
485 // reset maResponseNames when collecting properties
486 maResponseNames.clear();
487 }
488 break;
489 }
490 case WebDAVName_resourcetype:
491 {
492 // resourcetype start, reset collection
493 mbResourceTypeCollection = false;
494 break;
495 }
496 case WebDAVName_supportedlock:
497 {
498 // supportedlock start, reset maLockEntries
499 maLockEntries.realloc(0);
500 break;
501 }
502 case WebDAVName_lockentry:
503 {
504 // lockentry start, reset maLockEntries
505 mbLockScopeSet = false;
506 mbLockTypeSet = false;
507 break;
508 }
509 case WebDAVName_activelock:
510 {
511 maLock = ucb::Lock();
512 break;
513 }
514 }
515 break;
516 }
517 case WebDAVNamespace_ucb_openoffice_org_dav_props:
518 {
519 break;
520 }
521 }
522 }
523 }
524 }
525
526 OUString MakePropertyName(WebDAVContext const& rContext)
527 {
528 OUString ret;
529 OString const name(OUStringToOString(rContext.getName(), RTL_TEXTENCODING_UTF8));
530 OString const nameSpace(OUStringToOString(rContext.getNamespace(), RTL_TEXTENCODING_UTF8));
531 DAVProperties::createUCBPropName(nameSpace.getStr(), name.getStr(), ret);
532 return ret;
533 }
534
535 void SAL_CALL WebDAVResponseParser::endElement( const OUString& aName )
536 {
537 const sal_Int32 nLen(aName.getLength());
538 SAL_WARN_IF(!mpContext, "ucb.ucp.webdav", "Parser EndElement without content (!)");
539
540 if(mpContext && nLen)
541 {
542 if(collectThisPropertyAsName())
543 {
544 // name must be encoded as expected by createSerfPropName()
545 OUString const name(MakePropertyName(*mpContext));
546 maPropStatNames.emplace_back(name);
547 }
548 else
549 {
550 switch(mpContext->getWebDAVNamespace())
551 {
552 default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
553 {
554 break;
555 }
556 case WebDAVNamespace_DAV:
557 {
558 switch(mpContext->getWebDAVName())
559 {
560 default: // WebDAVName_unknown, WebDAVName_last or unhandled
561 {
562 break;
563 }
564 case WebDAVName_href:
565 {
566 // href end, save it if we have whitespace
567 if(whitespaceIsAvailable())
568 {
569 // Sharepoint 2016 workaround: apparently
570 // the result is an IRI (RFC 3987 possibly?)
571 // so try to encode the non-ASCII chars
572 // without changing anything else
573 maHref = ::rtl::Uri::encode(mpContext->getWhiteSpace(),
574 rtl_UriCharClassUric, rtl_UriEncodeKeepEscapes,
575 RTL_TEXTENCODING_UTF8);
576 }
577 break;
578 }
579 case WebDAVName_status:
580 {
581 // status end, save it if we have whitespace
582 if(whitespaceIsAvailable())
583 {
584 maStatus = mpContext->getWhiteSpace();
585 }
586 break;
587 }
588 case WebDAVName_getlastmodified:
589 {
590 // getlastmodified end, safe if content is correct
591 if(propertyIsReady())
592 {
593 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
594
595 aDAVPropertyValue.Name = "DAV:getlastmodified";
596 aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
597 maPropStatProperties.push_back(aDAVPropertyValue);
598 }
599 break;
600 }
601 case WebDAVName_creationdate:
602 {
603 // creationdate end, safe if content is correct
604 if(propertyIsReady())
605 {
606 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
607
608 aDAVPropertyValue.Name = "DAV:creationdate";
609 aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
610 maPropStatProperties.push_back(aDAVPropertyValue);
611 }
612 break;
613 }
614 case WebDAVName_collection:
615 {
616 // collection end, check and set
617 if(hasParent(WebDAVName_resourcetype))
618 {
619 mbResourceTypeCollection = true;
620 }
621 break;
622 }
623 case WebDAVName_resourcetype:
624 {
625 // resourcetype end, check for collection
626 if(hasParent(WebDAVName_prop))
627 {
628 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
629
630 aDAVPropertyValue.Name = "DAV:resourcetype";
631 aDAVPropertyValue.Value <<= (mbResourceTypeCollection ? OUString("collection") : OUString());
632 maPropStatProperties.push_back(aDAVPropertyValue);
633 }
634 break;
635 }
636 case WebDAVName_getcontentlength:
637 {
638 // getcontentlength end, safe if content is correct
639 if(propertyIsReady())
640 {
641 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
642
643 aDAVPropertyValue.Name = "DAV:getcontentlength";
644 aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
645 maPropStatProperties.push_back(aDAVPropertyValue);
646 }
647 break;
648 }
649 case WebDAVName_getcontenttype:
650 {
651 // getcontenttype end, safe if content is correct
652 if(propertyIsReady())
653 {
654 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
655
656 aDAVPropertyValue.Name = "DAV:getcontenttype";
657 aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
658 maPropStatProperties.push_back(aDAVPropertyValue);
659 }
660 break;
661 }
662 case WebDAVName_supportedlock:
663 {
664 // supportedlock end
665 if(hasParent(WebDAVName_prop) && maLockEntries.hasElements())
666 {
667 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
668
669 aDAVPropertyValue.Name = "DAV:supportedlock";
670 aDAVPropertyValue.Value <<= maLockEntries;
671 maPropStatProperties.push_back(aDAVPropertyValue);
672 }
673 break;
674 }
675 case WebDAVName_lockentry:
676 {
677 // lockentry end
678 if(hasParent(WebDAVName_supportedlock) && (mbLockScopeSet && mbLockTypeSet))
679 {
680 const sal_Int32 nLength(maLockEntries.getLength());
681 ucb::LockEntry aEntry;
682
683 aEntry.Scope = maLockScope;
684 aEntry.Type = maLockType;
685 maLockEntries.realloc(nLength + 1);
686 maLockEntries.getArray()[nLength] = aEntry;
687 }
688 break;
689 }
690 case WebDAVName_owner:
691 {
692 maLock.Owner <<= mpContext->getWhiteSpace();
693 break;
694 }
695 case WebDAVName_timeout:
696 {
697 const OUString sTimeout(mpContext->getWhiteSpace());
698 if (sTimeout == "Infinite")
699 maLock.Timeout = -1;
700 else if (sTimeout.startsWith("Second-"))
701 maLock.Timeout = o3tl::toInt64(sTimeout.subView(7));
702 break;
703 }
704 case WebDAVName_locktoken:
705 {
706 const OUString sLockToken(maHref);
707 SAL_WARN_IF(!sLockToken.startsWith("opaquelocktoken:"), "ucb.ucp.webdav",
708 "Parser error: wrong 'locktoken' value.");
709 const sal_Int32 nLength(maLock.LockTokens.getLength());
710 maLock.LockTokens.realloc(nLength+1);
711 maLock.LockTokens.getArray()[nLength] = sLockToken;
712 break;
713 }
714 case WebDAVName_exclusive:
715 {
716 // exclusive lockscope end
717 if(hasParent(WebDAVName_lockscope))
718 {
719 maLockScope = ucb::LockScope_EXCLUSIVE;
720 mbLockScopeSet = true;
721 }
722 break;
723 }
724 case WebDAVName_shared:
725 {
726 // shared lockscope end
727 if(hasParent(WebDAVName_lockscope))
728 {
729 maLockScope = ucb::LockScope_SHARED;
730 mbLockScopeSet = true;
731 }
732 break;
733 }
734 case WebDAVName_write:
735 {
736 // write locktype end
737 if(hasParent(WebDAVName_locktype))
738 {
739 maLockType = ucb::LockType_WRITE;
740 mbLockTypeSet = true;
741 }
742 break;
743 }
744 case WebDAVName_depth:
745 {
746 OUString const chars(mpContext->getWhiteSpace());
747 if (chars == "0")
748 {
749 maLock.Depth = ucb::LockDepth_ZERO;
750 }
751 else if (chars == "1")
752 {
753 maLock.Depth = ucb::LockDepth_ONE;
754 }
755 else if (chars == "infinity")
756 {
757 maLock.Depth = ucb::LockDepth_INFINITY;
758 }
759 break;
760 }
761 case WebDAVName_activelock:
762 {
763 maLock.Type = maLockType;
764 maLock.Scope = maLockScope;
765 maResult_Lock.push_back(maLock);
766 break;
767 }
768 case WebDAVName_lockdiscovery:
769 {
770 // lockdiscovery may be requested via PROPFIND,
771 // in addition to LOCK! so return it 2 ways
772 if (isCollectingProperties())
773 {
774 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
775
776 aDAVPropertyValue.Name = "DAV:lockdiscovery";
777 aDAVPropertyValue.Value <<= ::comphelper::containerToSequence(maResult_Lock);
778 maPropStatProperties.push_back(aDAVPropertyValue);
779 }
780 break;
781 }
782 case WebDAVName_propstat:
783 {
784 // propstat end, check status
785 if(maStatus.getLength())
786 {
787 if(maStatus == "HTTP/1.1 200 OK")
788 {
789 if(isCollectingProperties())
790 {
791 if(!maPropStatProperties.empty())
792 {
793 // append to maResponseProperties if okay
794 maResponseProperties.insert(maResponseProperties.end(), maPropStatProperties.begin(), maPropStatProperties.end());
795 }
796 }
797 else
798 {
799 if(!maPropStatNames.empty())
800 {
801 // when collecting properties append to
802 maResponseNames.insert(maResponseNames.end(), maPropStatNames.begin(), maPropStatNames.end());
803 }
804 }
805 }
806 }
807 break;
808 }
809 case WebDAVName_response:
810 {
811 // response end
812 if(maHref.getLength())
813 {
814 if(isCollectingProperties())
815 {
816 // create DAVResource when we have content
817 if(!maResponseProperties.empty())
818 {
819 http_dav_ucp::DAVResource aDAVResource;
820
821 aDAVResource.uri = maHref;
822 aDAVResource.properties = maResponseProperties;
823 maResult_PropFind.push_back(aDAVResource);
824 }
825 }
826 else
827 {
828 // when collecting properties add them to result when there are some
829 if(!maResponseNames.empty())
830 {
831 http_dav_ucp::DAVResourceInfo aDAVResourceInfo;
832
833 aDAVResourceInfo.properties = maResponseNames;
834 maResult_PropName.push_back(aDAVResourceInfo);
835 }
836 }
837 }
838 break;
839 }
840 }
841 break;
842 }
843 case WebDAVNamespace_ucb_openoffice_org_dav_props:
844 {
845 switch(mpContext->getWebDAVName())
846 {
847 case WebDAVName_type:
848 {
849 m_UCBType = mpContext->getWhiteSpace();
850 break;
851 }
852 case WebDAVName_value:
853 {
854 m_UCBValue = mpContext->getWhiteSpace();
855 break;
856 }
857 case WebDAVName_ucbprop:
858 {
859 if (!m_UCBType.isEmpty()
860 && isCollectingProperties())
861 {
862 http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
863 aDAVPropertyValue.Name = MakePropertyName(*mpContext->getParent());
864 if (UCBDeadPropertyValue::createFromXML(m_UCBType, m_UCBValue, aDAVPropertyValue.Value))
865 {
866 maPropStatProperties.push_back(aDAVPropertyValue);
867 }
868 else
869 {
870 SAL_INFO("ucb.ucp.webdav.curl", "cannot parse property value");
871 }
872 }
873 m_UCBType.clear();
874 m_UCBValue.clear();
875 break;
876 }
877 default:
878 break;
879 }
880 break;
881 }
882 }
883 }
884
885 // destroy last context (pop)
886 pop_context();
887 }
888 }
889
890 void SAL_CALL WebDAVResponseParser::characters( const OUString& aChars )
891 {
892 // collect whitespace over evtl. several calls in mpContext
893 SAL_WARN_IF(!mpContext, "ucb.ucp.webdav", "Parser characters without content (!)");
894 const sal_Int32 nLen(aChars.getLength());
895
896 if(mpContext && nLen)
897 {
898 // remove leading/trailing blanks and CRLF
899 const OUString aTrimmedChars(aChars.trim());
900
901 if(aTrimmedChars.getLength())
902 {
903 OUString aNew(mpContext->getWhiteSpace());
904
905 if(aNew.getLength())
906 {
907 // add one char when appending (see html1.1 spec)
908 aNew += " ";
909 }
910
911 aNew += aTrimmedChars;
912 mpContext->setWhiteSpace(aNew);
913 }
914 }
915 }
916
917 void SAL_CALL WebDAVResponseParser::ignorableWhitespace( const OUString& /*aWhitespaces*/ )
918 {
919 }
920
921 void SAL_CALL WebDAVResponseParser::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ )
922 {
923 }
924
925 void SAL_CALL WebDAVResponseParser::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ )
926 {
927 }
928} // end of anonymous namespace
929
930
931// wrapper for various calls to the parser
932
933namespace
934{
935 template<typename T>
936 void parseWebDAVResponse(
937 const uno::Reference< io::XInputStream >& xInputStream,
938 std::vector< T >& rResult,
939 WebDAVResponseParserMode eWebDAVResponseParserMode,
940 std::vector<T> const & (WebDAVResponseParser::* fn)() const)
941 {
942 if(xInputStream.is())
943 {
944 try
945 {
946 // prepare ParserInputSource
947 xml::sax::InputSource myInputSource;
948 myInputSource.aInputStream = xInputStream;
949
950 // get parser
951 uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(
953
954 // create parser; connect parser and filter
955 rtl::Reference<WebDAVResponseParser> const pWebDAVResponseParser(
956 new WebDAVResponseParser(eWebDAVResponseParserMode));
957 uno::Reference< xml::sax::XDocumentHandler > xWebDAVHdl(pWebDAVResponseParser);
958 xParser->setDocumentHandler(xWebDAVHdl);
959
960 // finally, parse the stream
961 xParser->parseStream(myInputSource);
962
963 // get result
964 rResult = (pWebDAVResponseParser.get()->*fn)();
965 }
966 catch(uno::Exception&)
967 {
968 SAL_WARN("ucb.ucp.webdav", "WebDAV Parse error (!)");
969 }
970 }
971 }
972} // end of anonymous namespace
973
974
975// helper to parse a XML WebDAV response
976
977namespace http_dav_ucp
978{
979 std::vector< ucb::Lock > parseWebDAVLockResponse(const uno::Reference< io::XInputStream >& xInputStream)
980 {
981 std::vector< ucb::Lock > aResult;
982 parseWebDAVResponse< ucb::Lock >(xInputStream, aResult, WebDAVResponseParserMode_Lock, &WebDAVResponseParser::getResult_Lock);
983 return aResult;
984 }
985
986 std::vector< DAVResource > parseWebDAVPropFindResponse(const uno::Reference< io::XInputStream >& xInputStream)
987 {
988 std::vector< DAVResource > aResult;
989 parseWebDAVResponse< DAVResource >(xInputStream, aResult, WebDAVResponseParserMode_PropFind, &WebDAVResponseParser::getResult_PropFind);
990 return aResult;
991 }
992
993 std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const uno::Reference< io::XInputStream >& xInputStream)
994 {
995 std::vector< DAVResourceInfo > aResult;
996 parseWebDAVResponse< DAVResourceInfo >(xInputStream, aResult, WebDAVResponseParserMode_PropName, &WebDAVResponseParser::getResult_PropName);
997 return aResult;
998 }
999} // namespace http_dav_ucp
1000
1001/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString maName
RegionData_Impl * mpParent
const char * name
sal_Int32 nIndex
OUString aName
uno_Any a
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
Reference< XComponentContext > getProcessComponentContext()
std::vector< ucb::Lock > parseWebDAVLockResponse(const uno::Reference< io::XInputStream > &xInputStream)
std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const uno::Reference< io::XInputStream > &xInputStream)
std::vector< DAVResource > parseWebDAVPropFindResponse(const uno::Reference< io::XInputStream > &xInputStream)
sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix=10)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
sal_Int16 nAttributes
ParserContextSharedPtr mpContext
std::vector< OUString > properties
Definition: DAVResource.hxx:48
std::vector< DAVPropertyValue > properties
Definition: DAVResource.hxx:43
sal_Int32 nLength