42 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEFUNCTION, CurlVectorReadOp::WriteCallback);
43 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEDATA,
this);
46 auto multiple =
false;
48 if (!chunk.GetLength())
continue;
49 if (multiple) {ss <<
",";}
50 ss << chunk.GetOffset() <<
"-" << chunk.GetOffset() + chunk.GetLength() - 1;
53 auto byte_range_val = ss.str();
54 if (byte_range_val.size()) {
63 std::string custom_msg = msg;
66 std::string offset =
"(unknown)";
67 std::string length =
"(unknown)";
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 +
")";
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);
81 handle->HandleResponse(status,
nullptr);
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);
138 m_current_op.second = std::numeric_limits<off_t>::max();
141 }
else if (!
m_headers.IsMultipartByterange()) {
143 m_current_op.second = std::numeric_limits<off_t>::max();
146 auto buffer = orig_buffer;
147 auto length = orig_length;
166 auto to_copy = (
static_cast<size_t>(remaining) < length) ?
static_cast<size_t>(remaining) : length;
185 CalculateNextBuffer();
212 auto get_next_line = [&]() {
213 std::string_view chunk_header(buffer, length);
214 auto pos = chunk_header.find(
"\r\n");
215 if (pos == std::string_view::npos) {
218 return std::make_pair(std::string_view(),
false);
220 auto line = chunk_header.substr(0, pos);
227 return std::make_pair(line,
true);
232 bool last_segment =
false;
234 auto [line, ok] = get_next_line();
241 if (line.empty()) {
continue;}
242 if (line ==
m_headers.MultipartSeparator()) {
245 if (line ==
m_headers.MultipartSeparator() +
"--") {
249 std::stringstream ss;
250 ss <<
"Server has responded with an invalid boundary line: '" << line <<
"' (expected '" <<
m_headers.MultipartSeparator() <<
"')";
259 auto [line, ok] = get_next_line();
266 auto header_name_end = line.find(
':');
267 if (header_name_end == std::string_view::npos) {
268 std::stringstream ss; ss <<
"Invalid header line in response from server: " << line;
271 auto header_name = line.substr(0, header_name_end);
274 if (header_name.size() != 13 || strncasecmp(header_name.data(),
"content-range", 13)) {
279 auto value = line.substr(header_name_end + 1);
282 while (!value.empty() && value[0] ==
' ') {
283 value = value.substr(1);
286 if (value.substr(0, 5) !=
"bytes") {
287 std::stringstream ss; ss <<
"Invalid Content-Range value (no 'bytes' unit): " << value;
291 value = value.substr(5);
292 while (!value.empty() && value[0] ==
' ') {
293 value = value.substr(1);
304 bytes_val = std::stoll(value.data(), &count);
305 }
catch (std::invalid_argument &) {
306 std::stringstream ss; ss <<
"Invalid Content-Range value (no integer in range start): " << value;
308 }
catch (std::out_of_range &) {
309 std::stringstream ss; ss <<
"Invalid Content-Range value (out of range): " << value;
312 if (value.size() <= count || value[count] !=
'-') {
313 std::stringstream ss; ss <<
"Invalid Content-Range value (no dash in range): " << value;
317 value = value.substr(count + 1);
319 bytes_val = std::stoll(value.data(), &count);
320 }
catch (std::invalid_argument &) {
321 std::stringstream ss; ss <<
"Invalid Content-Range value (no integer in range end): " << value;
323 }
catch (std::out_of_range &) {
324 std::stringstream ss; ss <<
"Invalid Content-Range value (out of range in range end): " << value;
327 if (value.size() <= count || value[count] !=
'/') {
328 std::stringstream ss; ss <<
"Invalid Content-Range value (no trailing /): " << value;
333 std::stringstream ss; ss <<
"Invalid Content-Range value (negative length): " << line;
336 if (length > std::numeric_limits<
decltype(
m_current_op.second)>::max()) {
337 std::stringstream ss; ss <<
"Invalid Content-Range value (length too long): " << line;
343 CalculateNextBuffer();
CurlOperation(XrdCl::ResponseHandler *handler, const std::string &url, struct timespec timeout, XrdCl::Log *log, CreateConnCalloutType, HeaderCallout *header_callout)
CurlVectorReadOp(XrdCl::ResponseHandler *handler, const std::string &url, struct timespec timeout, const XrdCl::ChunkList &op_list, XrdCl::Log *logger, CreateConnCalloutType callout, HeaderCallout *header_callout)