XRootD
XrdClHttp::CurlVectorReadOp Class Reference

#include <XrdClHttpOps.hh>

+ Inheritance diagram for XrdClHttp::CurlVectorReadOp:
+ Collaboration diagram for XrdClHttp::CurlVectorReadOp:

Public Member Functions

 CurlVectorReadOp (XrdCl::ResponseHandler *handler, const std::string &url, struct timespec timeout, const XrdCl::ChunkList &op_list, XrdCl::Log *logger, CreateConnCalloutType callout, HeaderCallout *header_callout)
 
virtual ~CurlVectorReadOp ()
 
void Fail (uint16_t errCode, uint32_t errNum, const std::string &msg) override
 
virtual HttpVerb GetVerb () const override
 
void ReleaseHandle () override
 
void SetSeparator (const std::string &sep)
 
void SetStatusCode (int sc)
 
bool Setup (CURL *curl, CurlWorker &) override
 
void Success () override
 
size_t Write (char *buffer, size_t size)
 
- Public Member Functions inherited from XrdClHttp::CurlOperation
 CurlOperation (const CurlOperation &)=delete
 
 CurlOperation (XrdCl::ResponseHandler *handler, const std::string &url, std::chrono::steady_clock::time_point expiry, XrdCl::Log *log, CreateConnCalloutType, HeaderCallout *header_callout)
 
 CurlOperation (XrdCl::ResponseHandler *handler, const std::string &url, struct timespec timeout, XrdCl::Log *log, CreateConnCalloutType, HeaderCallout *header_callout)
 
virtual ~CurlOperation ()
 
virtual bool ContinueHandle ()
 
void ExtendDeadline (struct timespec timeout)
 
bool FinishSetup (CURL *curl)
 
std::pair< XErrorCode, std::string > GetCallbackError () const
 
CreateConnCalloutType GetConnCalloutFunc () const
 
std::string GetCurlErrorMessage () const
 
CURL * GetCurlHandle () const
 
OpError GetError () const
 
std::chrono::steady_clock::time_point GetHeaderExpiry () const
 
std::chrono::steady_clock::time_point GetOperationExpiry ()
 
std::unique_ptr< ResponseInfo > GetResponseInfo ()
 
int GetStatusCode () const
 
std::string GetStatusMessage () const
 
bool GetTriedBoker () const
 
const std::string & GetUrl () const
 
bool HasFailed () const
 
bool HeaderTimeoutExpired (const std::chrono::steady_clock::time_point &now)
 
bool IsDone () const
 
bool IsPaused () const
 
bool IsRedirect () const
 
std::unique_ptr< ResponseInfo > MoveResponseInfo ()
 
bool OperationTimeoutExpired (const std::chrono::steady_clock::time_point &now)
 
virtual void OptionsDone ()
 
virtual RedirectAction Redirect (std::string &target)
 
virtual bool RequiresOptions () const
 
virtual void SetContinueQueue (std::shared_ptr< XrdClHttp::HandlerQueue > queue)
 
void SetTriedBoker ()
 
bool StartConnectionCallout (std::string &err)
 
std::tuple< uint64_t, std::chrono::steady_clock::duration, std::chrono::steady_clock::duration, std::chrono::steady_clock::duration > StatisticsReset ()
 
bool TransferStalled (uint64_t xfer_bytes, const std::chrono::steady_clock::time_point &now)
 
bool UseConnectionCallout ()
 
virtual int WaitSocket ()
 
virtual int WaitSocketCallback (std::string &err)
 

Protected Attributes

off_t m_bytes_consumed {0}
 
off_t m_chunk_buffer_idx {0}
 
XrdCl::ChunkList m_chunk_list
 
std::pair< off_t, off_t > m_current_op {-1, -1}
 
std::string m_header_line
 
std::string m_response_headers
 
size_t m_response_idx {0}
 
uint64_t m_skip_bytes {0}
 
std::unique_ptr< XrdCl::VectorReadInfo > m_vr
 
- Protected Attributes inherited from XrdClHttp::CurlOperation
std::unique_ptr< CURL, void(*)(CURL *)> m_curl
 
XrdCl::ResponseHandler * m_handler {nullptr}
 
HeaderCallout * m_header_callout
 
std::atomic< std::chrono::steady_clock::time_point > m_header_expiry
 
HeaderParser m_headers
 
std::vector< std::pair< std::string, std::string > > m_headers_list
 
XrdCl::Log * m_logger
 
int m_minimum_rate {m_minimum_transfer_rate}
 
std::chrono::steady_clock::time_point m_operation_expiry
 
std::string m_request_url
 
const std::string m_url
 

Additional Inherited Members

- Public Types inherited from XrdClHttp::CurlOperation
using HeaderList = std::vector< std::pair< std::string, std::string > >
 
using HttpVerb = XrdClHttp::HttpVerb
 
enum  OpError {
  ErrNone ,
  ErrHeaderTimeout ,
  ErrCallback ,
  ErrOperationTimeout ,
  ErrTransferClientStall ,
  ErrTransferStall ,
  ErrTransferSlow
}
 
enum class  RedirectAction {
  Fail ,
  Reinvoke ,
  ReinvokeAfterAllow
}
 
- Static Public Member Functions inherited from XrdClHttp::CurlOperation
static void CleanupDnsCache ()
 
static int GetDefaultSlowRateBytesSec ()
 
static int GetDefaultStallTimeout ()
 
static const std::string GetVerbString (HttpVerb)
 
static void SetSlowRateBytesSec (int rate)
 
static void SetStallTimeout (const std::chrono::steady_clock::duration &stall_interval)
 
static void SetStallTimeout (int stall_interval)
 
- Protected Member Functions inherited from XrdClHttp::CurlOperation
int FailCallback (XErrorCode ecode, const std::string &emsg)
 
void SetDone (bool has_failed)
 
void SetPaused (bool paused)
 
bool SetupNextRequest (const std::string &url, CurlWorker &worker)
 
void UpdateBytes (uint64_t bytes)
 
- Static Protected Attributes inherited from XrdClHttp::CurlOperation
static constexpr int m_default_minimum_rate {1024 * 256}
 
static int m_minimum_transfer_rate {CurlOperation::m_default_minimum_rate}
 

Detailed Description

Definition at line 768 of file XrdClHttpOps.hh.

Constructor & Destructor Documentation

◆ CurlVectorReadOp()

CurlVectorReadOp::CurlVectorReadOp ( XrdCl::ResponseHandler *  handler,
const std::string &  url,
struct timespec  timeout,
const XrdCl::ChunkList &  op_list,
XrdCl::Log *  logger,
CreateConnCalloutType  callout,
HeaderCallout *  header_callout 
)

Definition at line 30 of file XrdClHttpOpReadV.cc.

32  :
33  CurlOperation(handler, url, timeout, logger, callout, header_callout),
35  m_chunk_list(op_list)
36  {}
CurlOperation(XrdCl::ResponseHandler *handler, const std::string &url, struct timespec timeout, XrdCl::Log *log, CreateConnCalloutType, HeaderCallout *header_callout)
XrdCl::ChunkList m_chunk_list
std::unique_ptr< XrdCl::VectorReadInfo > m_vr

◆ ~CurlVectorReadOp()

virtual XrdClHttp::CurlVectorReadOp::~CurlVectorReadOp ( )
inlinevirtual

Definition at line 774 of file XrdClHttpOps.hh.

774 {}

Member Function Documentation

◆ Fail()

void CurlVectorReadOp::Fail ( uint16_t  errCode,
uint32_t  errNum,
const std::string &  msg 
)
overridevirtual

Reimplemented from XrdClHttp::CurlOperation.

Definition at line 61 of file XrdClHttpOpReadV.cc.

62 {
63  std::string custom_msg = msg;
64  SetDone(true);
65  if (m_handler == nullptr) {return;}
66  std::string offset = "(unknown)";
67  std::string length = "(unknown)";
68  if (!m_chunk_list.empty()) {
69  offset = std::to_string(m_chunk_list[0].GetOffset());
70  length = std::to_string(m_chunk_list[0].GetLength());
71  }
72  if (!custom_msg.empty()) {
73  m_logger->Debug(kLogXrdClHttp, "curl operation with vector starting offset %s / length %s failed with message: %s", offset.c_str(), length.c_str(), custom_msg.c_str());
74  custom_msg += " (vector read operation starting at offset " + offset + " / length " + length + ")";
75  } else {
76  m_logger->Debug(kLogXrdClHttp, "curl vector operation starting at offset %s / length %s failed with status code %d", offset.c_str(), length.c_str(), errNum);
77  }
78  auto status = new XrdCl::XRootDStatus(XrdCl::stError, errCode, errNum, custom_msg);
79  auto handle = m_handler;
80  m_handler = nullptr;
81  handle->HandleResponse(status, nullptr);
82 }
void SetDone(bool has_failed)
XrdCl::ResponseHandler * m_handler
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition: XrdClLog.cc:282
virtual void HandleResponse(XRootDStatus *status, AnyObject *response)
const uint16_t stError
An error occurred that could potentially be retried.
Definition: XrdClStatus.hh:32
const uint64_t kLogXrdClHttp

References XrdCl::Log::Debug(), XrdCl::ResponseHandler::HandleResponse(), XrdClHttp::kLogXrdClHttp, m_chunk_list, XrdClHttp::CurlOperation::m_handler, XrdClHttp::CurlOperation::m_logger, XrdClHttp::CurlOperation::SetDone(), and XrdCl::stError.

+ Here is the call graph for this function:

◆ GetVerb()

virtual HttpVerb XrdClHttp::CurlVectorReadOp::GetVerb ( ) const
inlineoverridevirtual

Implements XrdClHttp::CurlOperation.

Definition at line 795 of file XrdClHttpOps.hh.

795 {return HttpVerb::GET;}

◆ ReleaseHandle()

void CurlVectorReadOp::ReleaseHandle ( )
overridevirtual

Reimplemented from XrdClHttp::CurlOperation.

Definition at line 107 of file XrdClHttpOpReadV.cc.

108 {
109  if (m_curl == nullptr) return;
110  curl_easy_setopt(m_curl.get(), CURLOPT_WRITEFUNCTION, nullptr);
111  curl_easy_setopt(m_curl.get(), CURLOPT_WRITEDATA, nullptr);
112  curl_easy_setopt(m_curl.get(), CURLOPT_HTTPHEADER, nullptr);
113  curl_easy_setopt(m_curl.get(), CURLOPT_OPENSOCKETFUNCTION, nullptr);
114  curl_easy_setopt(m_curl.get(), CURLOPT_OPENSOCKETDATA, nullptr);
115  curl_easy_setopt(m_curl.get(), CURLOPT_SOCKOPTFUNCTION, nullptr);
116  curl_easy_setopt(m_curl.get(), CURLOPT_SOCKOPTDATA, nullptr);
118 }
std::unique_ptr< CURL, void(*)(CURL *)> m_curl
virtual void ReleaseHandle()

References XrdClHttp::CurlOperation::m_curl, and XrdClHttp::CurlOperation::ReleaseHandle().

+ Here is the call graph for this function:

◆ SetSeparator()

void XrdClHttp::CurlVectorReadOp::SetSeparator ( const std::string &  sep)
inline

Definition at line 783 of file XrdClHttpOps.hh.

783  {
785  }
void SetMultipartSeparator(const std::string_view &sep)

References XrdClHttp::CurlOperation::m_headers, and XrdClHttp::HeaderParser::SetMultipartSeparator().

+ Here is the call graph for this function:

◆ SetStatusCode()

void XrdClHttp::CurlVectorReadOp::SetStatusCode ( int  sc)
inline

Definition at line 788 of file XrdClHttpOps.hh.

References XrdClHttp::CurlOperation::m_headers, and XrdClHttp::HeaderParser::SetStatusCode().

+ Here is the call graph for this function:

◆ Setup()

bool CurlVectorReadOp::Setup ( CURL *  curl,
CurlWorker &  worker 
)
overridevirtual

Reimplemented from XrdClHttp::CurlOperation.

Definition at line 39 of file XrdClHttpOpReadV.cc.

40 {
41  if (!CurlOperation::Setup(curl, worker)) return false;
42  curl_easy_setopt(m_curl.get(), CURLOPT_WRITEFUNCTION, CurlVectorReadOp::WriteCallback);
43  curl_easy_setopt(m_curl.get(), CURLOPT_WRITEDATA, this);
44 
45  std::stringstream ss;
46  auto multiple = false;
47  for (const auto &chunk : m_chunk_list) {
48  if (!chunk.GetLength()) continue;
49  if (multiple) {ss << ",";}
50  ss << chunk.GetOffset() << "-" << chunk.GetOffset() + chunk.GetLength() - 1;
51  multiple = true;
52  }
53  auto byte_range_val = ss.str();
54  if (byte_range_val.size()) {
55  m_headers_list.emplace_back("Range", "bytes=" + byte_range_val);
56  }
57  return true;
58 }
std::vector< std::pair< std::string, std::string > > m_headers_list
virtual bool Setup(CURL *curl, CurlWorker &)

References m_chunk_list, XrdClHttp::CurlOperation::m_curl, XrdClHttp::CurlOperation::m_headers_list, and XrdClHttp::CurlOperation::Setup().

+ Here is the call graph for this function:

◆ Success()

void CurlVectorReadOp::Success ( )
overridevirtual

Implements XrdClHttp::CurlOperation.

Definition at line 85 of file XrdClHttpOpReadV.cc.

86 {
87  SetDone(false);
88  if (m_handler == nullptr) {return;}
89 
90  // If there's a partial last response, give it to the client.
91  if (m_chunk_buffer_idx) {
92  auto &chunk = m_chunk_list[m_response_idx];
93  m_vr->GetChunks().emplace_back(chunk.GetOffset(), m_chunk_buffer_idx, chunk.GetBuffer());
95  }
96 
97  auto status = new XrdCl::XRootDStatus();
98  m_vr->SetSize(m_bytes_consumed);
99  auto obj = new XrdCl::AnyObject();
100  obj->Set(m_vr.release());
101  auto handle = m_handler;
102  m_handler = nullptr;
103  handle->HandleResponse(status, obj);
104 }

References XrdCl::ResponseHandler::HandleResponse(), m_bytes_consumed, m_chunk_buffer_idx, m_chunk_list, XrdClHttp::CurlOperation::m_handler, m_response_idx, m_vr, and XrdClHttp::CurlOperation::SetDone().

+ Here is the call graph for this function:

◆ Write()

size_t CurlVectorReadOp::Write ( char *  buffer,
size_t  size 
)

Definition at line 128 of file XrdClHttpOpReadV.cc.

129 {
130  UpdateBytes(orig_length);
131  //m_logger->Debug(kLogXrdClHttp, "Received a write of size %ld with contents:\n%s", static_cast<long>(orig_length), std::string(orig_buffer, orig_length).c_str());
132 
133  // Handle the (hopefully uncommon) cases where the server responds to a vector read op
134  // with a single response. We set the length of the response to the max as we
135  // don't care how many bytes the server actually sends.
136  if (GetStatusCode() == 200) {
137  m_current_op.first = 0;
138  m_current_op.second = std::numeric_limits<off_t>::max();
139  } else if (HTTPStatusIsError(GetStatusCode())) {
140  return orig_length;
141  } else if (!m_headers.IsMultipartByterange()) {
142  m_current_op.first = m_headers.GetOffset();
143  m_current_op.second = std::numeric_limits<off_t>::max();
144  }
145 
146  auto buffer = orig_buffer;
147  auto length = orig_length;
148 
149  while (length) {
150  // If we're in the middle of a response chunk, copy as much data as possible.
151  // m_multipart_boundary is false while part headers are still being assembled
152  // across curl writes. Content-Range may already have filled m_current_op, but
153  // the terminating blank line (and thus the payload) has not arrived yet.
154  if (m_multipart_boundary && m_current_op.first != -1 && m_current_op.second != -1) {
155  //m_logger->Debug(kLogXrdClHttp, "Processing response buffer of (%lld, %lld)", static_cast<long long>(m_current_op.first), static_cast<long long>(m_current_op.second));
156  if (m_skip_bytes) {
157  //m_logger->Debug(kLogXrdClHttp, "Skipping %lld bytes", static_cast<long long>(m_skip_bytes));
158  auto to_skip = (m_skip_bytes < length) ? m_skip_bytes : length;
159  buffer += to_skip;
160  length -= to_skip;
161  m_skip_bytes -= to_skip;
162  continue;
163  } else {
164  auto &chunk = m_chunk_list[m_response_idx];
165  auto remaining = static_cast<off_t>(chunk.GetLength()) - m_chunk_buffer_idx;
166  if (remaining < 0) {
167  return FailCallback(kXR_ServerError, "Invalid chunk framing");
168  }
169  auto to_copy = (static_cast<size_t>(remaining) < length) ? static_cast<size_t>(remaining) : length;
170  //m_logger->Debug(kLogXrdClHttp, "Copying %lld bytes to request buffer %ld at offset %lld", static_cast<long long>(to_copy), m_response_idx, static_cast<long long>(m_chunk_buffer_idx));
171  memcpy(static_cast<char *>(chunk.GetBuffer()) + m_chunk_buffer_idx, buffer, to_copy);
172  m_chunk_buffer_idx += to_copy;
173  buffer += to_copy;
174  length -= to_copy;
175  // Handle cases where the requested or response chunk is complete
176  if (chunk.GetLength() == m_chunk_buffer_idx) {
177  m_vr->GetChunks().emplace_back(chunk.GetOffset(), m_chunk_buffer_idx, chunk.GetBuffer());
179  m_chunk_buffer_idx = 0;
180  m_response_idx++;
181  if (m_current_op.second == chunk.GetLength()) {
182  m_current_op.first = m_current_op.second = -1;
183  m_multipart_boundary = true;
184  } else {
185  // We may need to skip the remaining bytes or, potentially, the server
186  // coalesced two adjacent requests into one larger response.
187  m_current_op.first += chunk.GetLength();
188  m_current_op.second -= chunk.GetLength();
189  CalculateNextBuffer();
190  continue;
191  }
192  } else if (m_current_op.second == m_chunk_buffer_idx) {
193  // There are no more bytes in the response but the requested chunk hasn't finished.
194  // Add what we have to the results and create a new chunk on the request list from the remainder; perhaps
195  // the server will send it in the future.
196  m_chunk_list.emplace_back(chunk.GetOffset() + m_chunk_buffer_idx, chunk.GetLength() - m_chunk_buffer_idx, static_cast<char*>(chunk.GetBuffer()) + m_chunk_buffer_idx);
197  m_vr->GetChunks().emplace_back(chunk.GetOffset(), m_chunk_buffer_idx, chunk.GetBuffer());
199  m_chunk_buffer_idx = 0;
200  m_current_op.first = m_current_op.second = -1;
201  m_multipart_boundary = true;
202  m_response_idx++;
203  }
204  }
205  }
206  if (m_skip_bytes) {
207  continue;
208  }
209 
210  // We are at the boundary between chunks; we must parse header lines to understand the
211  // next thing to do.
212 
213  // The following lambda function returns a string view to the next complete header line,
214  // potentially partially from the previous buffer from curl. If the second item in
215  // the returned pair is false, then we ran out of buffer from curl before finding a
216  // complete line.
217  auto get_next_line = [&]() {
218  std::string_view chunk_header(buffer, length);
219  // CRLF may be split across curl writes: previous chunk ended with \r
220  // and this one starts with \n. find("\r\n") would otherwise glue this
221  // line to the next header (e.g. "--123456\r" + "\nContent-type: ...\r\n").
222  if (!m_response_headers.empty() && m_response_headers.back() == '\r' &&
223  !chunk_header.empty() && chunk_header.front() == '\n') {
224  m_response_headers.pop_back();
225  m_header_line = std::move(m_response_headers);
226  buffer += 1;
227  length -= 1;
228  return std::make_pair(std::string_view(m_header_line), true);
229  }
230  auto pos = chunk_header.find("\r\n");
231  if (pos == std::string_view::npos) {
232  m_response_headers += chunk_header;
233  length = 0;
234  return std::make_pair(std::string_view(), false);
235  } else {
236  auto line_part = chunk_header.substr(0, pos);
237  if (!m_response_headers.empty()) {
238  m_response_headers += line_part;
239  m_header_line = std::move(m_response_headers);
240  } else {
241  m_header_line.assign(line_part);
242  }
243  buffer += pos + 2;
244  length -= pos + 2;
245  return std::make_pair(std::string_view(m_header_line), true);
246  }
247  };
248 
249  // Consume the boundary line.
250  bool last_segment = false;
251  if (m_multipart_boundary) {
252  while (true) {
253  auto [line, ok] = get_next_line();
254  if (!ok) {
255  return orig_length;
256  }
257  // Per RFC7233, Appendix A, Implementation note 1, multiple CRLF might precede the
258  // first boundary string in the body. However, the XRootD server appears to have an
259  // extra CRLF in front of every boundary string.
260  if (line.empty()) {continue;}
261  if (line == m_headers.MultipartSeparator()) {
262  break;
263  }
264  if (line == m_headers.MultipartSeparator() + "--") {
265  last_segment = true;
266  break;
267  }
268  std::stringstream ss;
269  ss << "Server has responded with an invalid boundary line: '" << line << "' (expected '" << m_headers.MultipartSeparator() << "')";
270  return FailCallback(kXR_ServerError, ss.str());
271  }
272  }
273  if (last_segment) {
274  length = 0;
275  break;
276  }
277  // Consume the header lines
278  while (true) {
279  auto [line, ok] = get_next_line();
280  if (!ok) {
281  m_multipart_boundary = false;
282  return orig_length;
283  }
284  if (line.empty()) {
285  break;
286  }
287  auto header_name_end = line.find(':');
288  if (header_name_end == std::string_view::npos) {
289  std::stringstream ss; ss << "Invalid header line in response from server: " << line;
290  return FailCallback(kXR_ServerError, ss.str());
291  }
292  auto header_name = line.substr(0, header_name_end);
293  // Cannot use strcasecmp here as a string_view's data is not necessarily nul-terminated.
294  // len("content-type") == 13
295  if (header_name.size() != 13 || strncasecmp(header_name.data(), "content-range", 13)) {
296  continue;
297  }
298  // We are parsing a Content-Range value.
299  // Example: Content-Range: bytes 7000-7999/8000
300  auto value = line.substr(header_name_end + 1);
301 
302  // Advance whitespace
303  while (!value.empty() && value[0] == ' ') {
304  value = value.substr(1);
305  }
306 
307  if (value.substr(0, 5) != "bytes") {
308  std::stringstream ss; ss << "Invalid Content-Range value (no 'bytes' unit): " << value;
309  return FailCallback(kXR_ServerError, ss.str());
310  }
311 
312  value = value.substr(5);
313  while (!value.empty() && value[0] == ' ') {
314  value = value.substr(1);
315  }
316 
317  // Example: 500-999/8000
318  size_t count;
319  long long bytes_val;
320  try {
321  // It may seem strange to see the string_view data being passed to std::stoll here
322  // as it's not guaranteed to be null-terminated. However, by this point, we do know
323  // there's a CRLF in the buffer -- that is sufficient to guarantee the stoll search
324  // terminates before it goes out-of-bounds.
325  bytes_val = std::stoll(value.data(), &count);
326  } catch (std::invalid_argument &) {
327  std::stringstream ss; ss << "Invalid Content-Range value (no integer in range start): " << value;
328  return FailCallback(kXR_ServerError, ss.str());
329  } catch (std::out_of_range &) {
330  std::stringstream ss; ss << "Invalid Content-Range value (out of range): " << value;
331  return FailCallback(kXR_ServerError, ss.str());
332  }
333  if (value.size() <= count || value[count] != '-') {
334  std::stringstream ss; ss << "Invalid Content-Range value (no dash in range): " << value;
335  return FailCallback(kXR_ServerError, ss.str());
336  }
337  m_current_op.first = bytes_val;
338  value = value.substr(count + 1);
339  try {
340  bytes_val = std::stoll(value.data(), &count);
341  } catch (std::invalid_argument &) {
342  std::stringstream ss; ss << "Invalid Content-Range value (no integer in range end): " << value;
343  return FailCallback(kXR_ServerError, ss.str());
344  } catch (std::out_of_range &) {
345  std::stringstream ss; ss << "Invalid Content-Range value (out of range in range end): " << value;
346  return FailCallback(kXR_ServerError, ss.str());
347  }
348  if (value.size() <= count || value[count] != '/') {
349  std::stringstream ss; ss << "Invalid Content-Range value (no trailing /): " << value;
350  return FailCallback(kXR_ServerError, ss.str());
351  }
352  auto length = bytes_val + 1 - m_current_op.first;
353  if (length < 0) {
354  std::stringstream ss; ss << "Invalid Content-Range value (negative length): " << line;
355  return FailCallback(kXR_ServerError, ss.str());
356  }
357  if (length > std::numeric_limits<decltype(m_current_op.second)>::max()) {
358  std::stringstream ss; ss << "Invalid Content-Range value (length too long): " << line;
359  return FailCallback(kXR_ServerError, ss.str());
360  }
361  m_current_op.second = length;
362 
363  // We now have a valid response range; locate a buffer where we will copy the bytes into.
364  CalculateNextBuffer();
365  }
366  m_multipart_boundary = true;
367 
368  // Check to see if the Content-Range was missing.
369  if (!last_segment && (m_current_op.first == -1 || m_current_op.second == -1)) {
370  return FailCallback(kXR_ServerError, "Response segment is missing a Content-Range header");
371  }
372  }
373  return orig_length;
374 }
@ kXR_ServerError
Definition: XProtocol.hh:1044
int FailCallback(XErrorCode ecode, const std::string &emsg)
void UpdateBytes(uint64_t bytes)
std::pair< off_t, off_t > m_current_op
uint64_t GetOffset() const
bool IsMultipartByterange() const
const std::string & MultipartSeparator() const
bool HTTPStatusIsError(unsigned status)

References XrdClHttp::CurlOperation::FailCallback(), XrdClHttp::HeaderParser::GetOffset(), XrdClHttp::CurlOperation::GetStatusCode(), XrdClHttp::HTTPStatusIsError(), XrdClHttp::HeaderParser::IsMultipartByterange(), kXR_ServerError, m_bytes_consumed, m_chunk_buffer_idx, m_chunk_list, m_current_op, m_header_line, XrdClHttp::CurlOperation::m_headers, m_response_headers, m_response_idx, m_skip_bytes, m_vr, XrdClHttp::HeaderParser::MultipartSeparator(), and XrdClHttp::CurlOperation::UpdateBytes().

+ Here is the call graph for this function:

Member Data Documentation

◆ m_bytes_consumed

off_t XrdClHttp::CurlVectorReadOp::m_bytes_consumed {0}
protected

Definition at line 809 of file XrdClHttpOps.hh.

Referenced by Success(), and Write().

◆ m_chunk_buffer_idx

off_t XrdClHttp::CurlVectorReadOp::m_chunk_buffer_idx {0}
protected

Definition at line 808 of file XrdClHttpOps.hh.

Referenced by Success(), and Write().

◆ m_chunk_list

XrdCl::ChunkList XrdClHttp::CurlVectorReadOp::m_chunk_list
protected

Definition at line 815 of file XrdClHttpOps.hh.

Referenced by Fail(), Setup(), Success(), and Write().

◆ m_current_op

std::pair<off_t, off_t> XrdClHttp::CurlVectorReadOp::m_current_op {-1, -1}
protected

Definition at line 813 of file XrdClHttpOps.hh.

Referenced by Write().

◆ m_header_line

std::string XrdClHttp::CurlVectorReadOp::m_header_line
protected

Definition at line 812 of file XrdClHttpOps.hh.

Referenced by Write().

◆ m_response_headers

std::string XrdClHttp::CurlVectorReadOp::m_response_headers
protected

Definition at line 811 of file XrdClHttpOps.hh.

Referenced by Write().

◆ m_response_idx

size_t XrdClHttp::CurlVectorReadOp::m_response_idx {0}
protected

Definition at line 807 of file XrdClHttpOps.hh.

Referenced by Success(), and Write().

◆ m_skip_bytes

uint64_t XrdClHttp::CurlVectorReadOp::m_skip_bytes {0}
protected

Definition at line 810 of file XrdClHttpOps.hh.

Referenced by Write().

◆ m_vr

std::unique_ptr<XrdCl::VectorReadInfo> XrdClHttp::CurlVectorReadOp::m_vr
protected

Definition at line 814 of file XrdClHttpOps.hh.

Referenced by Success(), and Write().


The documentation for this class was generated from the following files: