LibreOffice Module ucb (master)  1
SerfLockReqProcImpl.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 
20 #include "SerfLockReqProcImpl.hxx"
21 
22 #include "AprEnv.hxx"
23 #include "SerfSession.hxx"
24 #include "DAVException.hxx"
25 
26 #include "webdavresponseparser.hxx"
27 #include <rtl/strbuf.hxx>
28 #include <sal/log.hxx>
29 
30 namespace http_dav_ucp
31 {
32 
34  const DAVRequestHeaders& inRequestHeaders,
35  SerfSession& rSession,
36  const css::ucb::Lock& rLock,
37  sal_Int32* plastChanceToSendRefreshRequest )
38  : SerfRequestProcessorImpl( inPath, inRequestHeaders )
39  , m_rSession( rSession )
40  , m_aLock( rLock )
41  , m_plastChanceToSendRefreshRequest( plastChanceToSendRefreshRequest )
42  , m_xInputStream( new SerfInputStream() )
43 {
44 }
45 
47 {
48 }
49 
50 serf_bucket_t * SerfLockReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest )
51 {
52  serf_bucket_alloc_t* pSerfBucketAlloc = serf_request_get_alloc( inSerfRequest );
53 
54  OStringBuffer aBody("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
55  "<lockinfo xmlns='DAV:'>\n <lockscope>");
56 
57  // Set the lock scope
58  switch ( m_aLock.Scope )
59  {
60  case css::ucb::LockScope_EXCLUSIVE:
61  aBody.append("<exclusive/>");
62  break;
63  case css::ucb::LockScope_SHARED:
64  aBody.append("<shared/>");
65  break;
66  default:
68  }
69  aBody.append("</lockscope>\n <locktype><write/></locktype>\n");
70 
71  // Set the lock owner
72  OUString aValue;
73  if ((m_aLock.Owner >>= aValue) && !aValue.isEmpty())
74  {
75  aBody.append(" <owner>");
76  aBody.append(OUStringToOString(aValue, RTL_TEXTENCODING_UTF8));
77  aBody.append("</owner>\n");
78  }
79  aBody.append("</lockinfo>\n");
80 
81  const OString aBodyText(aBody.makeStringAndClear());
82  serf_bucket_t* body_bkt = nullptr;
83 
85  body_bkt = serf_bucket_simple_copy_create( aBodyText.getStr(),
86  aBodyText.getLength(),
87  pSerfBucketAlloc );
88 
89  // create serf request
90  serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest,
91  "LOCK",
92  getPathStr(),
93  body_bkt,
94  pSerfBucketAlloc );
96  handleChunkedEncoding(req_bkt, aBodyText.getLength());
97 
98  // set request header fields
99  serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt );
100 
101  // general header fields provided by caller
102  setRequestHeaders( hdrs_bkt );
103 
104  // request specific header fields
105  const char * depth = nullptr;
106  switch( m_aLock.Depth )
107  {
108  case css::ucb::LockDepth_ZERO:
109  depth = "0";
110  break;
111  case css::ucb::LockDepth_ONE:
112  depth = "1";
113  break;
114  case css::ucb::LockDepth_INFINITY:
115  depth = "infinity";
116  break;
117  default:
119  }
121  {
122  serf_bucket_headers_set( hdrs_bkt, "Depth", depth );
123  serf_bucket_headers_set( hdrs_bkt, "Content-Type", "application/xml" );
124  }
125  else
126  {
127  const OString sToken( "(<" + OUStringToOString( apr_environment::AprEnv::getAprEnv()->
128  getSerfLockStore()->getLockToken( OUString::createFromAscii(getPathStr())),
129  RTL_TEXTENCODING_UTF8 ) + ">)" );
130  serf_bucket_headers_set( hdrs_bkt, "If", sToken.getStr() );
131  }
132 
133  // Set the lock timeout
134  if (m_aLock.Timeout == -1)
135  serf_bucket_headers_set( hdrs_bkt, "Timeout", "Infinite" );
136  else if (m_aLock.Timeout > 0)
137  {
138  const OString aTimeValue("Second-" + OString::number(m_aLock.Timeout));
139  serf_bucket_headers_set( hdrs_bkt, "Timeout", aTimeValue.getStr() );
140  }
141  else
142  serf_bucket_headers_set( hdrs_bkt, "Timeout", "Second-180" );
143 
144  osl_getSystemTime( &m_aStartCall );
145 
146  return req_bkt;
147 }
148 
150  apr_size_t len )
151 {
152  if ( m_xInputStream.is() )
153  {
154  m_xInputStream->AddToStream( data, len );
155  }
156 }
157 
159 {
160  const std::vector< css::ucb::Lock > aLocks( parseWebDAVLockResponse( m_xInputStream.get() ) );
161 
162  if (!aLocks.empty())
163  {
164  for (size_t i = 0; i < aLocks.size(); ++i)
165  {
166  sal_Int64 timeout = aLocks[i].Timeout;
167  TimeValue aEnd;
168  osl_getSystemTime( &aEnd );
169  // Try to estimate a safe absolute time for sending the
170  // lock refresh request.
171  sal_Int32 lastChanceToSendRefreshRequest = -1;
172  if ( timeout != -1 )
173  {
174  sal_Int32 calltime = aEnd.Seconds - m_aStartCall.Seconds;
175  if ( calltime <= timeout )
176  lastChanceToSendRefreshRequest = aEnd.Seconds + timeout - calltime;
177  else
178  SAL_WARN("ucb.ucp.webdav", "No chance to refresh lock before timeout!" );
179  }
181  {
182  *m_plastChanceToSendRefreshRequest = lastChanceToSendRefreshRequest;
183  assert(aLocks.size() == 1);
184  // We are just refreshing lock, do not add it into SerfLockStore
185  break;
186  }
188  OUString::createFromAscii(getPathStr()),
189  aLocks[i].LockTokens[0],
190  &m_rSession, lastChanceToSendRefreshRequest );
191  SAL_INFO("ucb.ucp.webdav", "SerfSession::LOCK: created lock for "
192  << getPathStr() << ". token: " << aLocks[i].LockTokens[0]);
193  }
194  }
195  else
196  {
197  SAL_INFO("ucb.ucp.webdav", "SerfSession::LOCK: obtaining lock failed!");
198  }
199 }
200 
201 } // namespace http_dav_ucp
202 
203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SerfLockReqProcImpl(const char *inPath, const DAVRequestHeaders &inRequestHeaders, SerfSession &rSession, const css::ucb::Lock &rLock, sal_Int32 *plastChanceToSendRefreshRequest=nullptr)
http_dav_ucp::SerfLockStore * getSerfLockStore()
Definition: AprEnv.cxx:57
void addLock(const OUString &rLock, const OUString &sToken, rtl::Reference< SerfSession > const &xSession, sal_Int32 nLastChanceToSendRefreshRequest)
std::vector< DAVRequestHeader > DAVRequestHeaders
std::vector< ucb::Lock > parseWebDAVLockResponse(const uno::Reference< io::XInputStream > &xInputStream)
void setRequestHeaders(serf_bucket_t *inoutSerfHeaderBucket)
void handleChunkedEncoding(serf_bucket_t *pRequestBucket, apr_int64_t nLength) const
Turn chunked encoding on or off, depending on the result of useChunkedEncoding(). ...
static AprEnv * getAprEnv()
Definition: AprEnv.cxx:45
virtual void handleEndOfResponseData(serf_bucket_t *inSerfResponseBucket) override
int i
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
virtual serf_bucket_t * createSerfRequestBucket(serf_request_t *inSerfRequest) override
#define SAL_INFO(area, stream)
virtual void processChunkOfResponseData(const char *data, apr_size_t len) override
#define SAL_WARN(area, stream)
rtl::Reference< SerfInputStream > m_xInputStream