XRootD
Loading...
Searching...
No Matches
XrdClHttpOpCopy.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* Copyright (C) 2025, Pelican Project, Morgridge Institute for Research */
3/* */
4/* This file is part of the XrdClHttp client plugin for XRootD. */
5/* */
6/* XRootD is free software: you can redistribute it and/or modify it under */
7/* the terms of the GNU Lesser General Public License as published by the */
8/* Free Software Foundation, either version 3 of the License, or (at your */
9/* option) any later version. */
10/* */
11/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
12/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
13/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
14/* License for more details. */
15/* */
16/* The copyright holder's institutional names and contributor's names may not */
17/* be used to endorse or promote products derived from this software without */
18/* specific prior written permission of the institution or contributor. */
19/******************************************************************************/
20
21#include "XrdClHttpOps.hh"
22
23using namespace XrdClHttp;
24
25CurlCopyOp::CurlCopyOp(XrdCl::ResponseHandler *handler, const std::string &source_url, const Headers &source_hdrs,
26 const std::string &dest_url, const Headers &dest_hdrs, struct timespec timeout, XrdCl::Log *logger,
27 CreateConnCalloutType callout) :
28 CurlOperation(handler, dest_url, timeout, logger, callout, nullptr),
29 m_source_url(source_url)
30 {
32
33 for (const auto &info : source_hdrs) {
34 m_headers_list.emplace_back(std::string("TransferHeader") + info.first, info.second);
35 }
36 for (const auto &info : dest_hdrs) {
37 m_headers_list.emplace_back(info.first, info.second);
38 }
39 }
40
41 bool
43 {
44 auto rv = CurlOperation::Setup(curl, worker);
45 if (!rv) return false;
46
47 curl_easy_setopt(m_curl.get(), CURLOPT_WRITEFUNCTION, CurlCopyOp::WriteCallback);
48 curl_easy_setopt(m_curl.get(), CURLOPT_WRITEDATA, this);
49 curl_easy_setopt(m_curl.get(), CURLOPT_CUSTOMREQUEST, "COPY");
50 m_headers_list.emplace_back("Source", m_source_url);
51
52 return true;
53 }
54
55 void
57 {
58 SetDone(false);
59 if (m_handler == nullptr) {return;}
60 auto status = new XrdCl::XRootDStatus();
61 auto obj = new XrdCl::AnyObject();
62 auto handle = m_handler;
63 m_handler = nullptr;
64 handle->HandleResponse(status, obj);
65 }
66
67 void
69 {
70 if (m_curl == nullptr) return;
71 curl_easy_setopt(m_curl.get(), CURLOPT_WRITEFUNCTION, nullptr);
72 curl_easy_setopt(m_curl.get(), CURLOPT_WRITEDATA, nullptr);
73 curl_easy_setopt(m_curl.get(), CURLOPT_CUSTOMREQUEST, nullptr);
74 curl_easy_setopt(m_curl.get(), CURLOPT_HTTPHEADER, nullptr);
75 curl_easy_setopt(m_curl.get(), CURLOPT_XFERINFOFUNCTION, nullptr);
77 }
78
79 size_t
80 CurlCopyOp::WriteCallback(char *buffer, size_t size, size_t nitems, void *this_ptr)
81 {
82 auto me = reinterpret_cast<CurlCopyOp*>(this_ptr);
83 me->UpdateBytes(size * nitems);
84 std::string_view str_data(buffer, size * nitems);
85 size_t end_line;
86 while ((end_line = str_data.find('\n')) != std::string_view::npos) {
87 auto cur_line = str_data.substr(0, end_line);
88 if (me->m_line_buffer.empty()) {
89 me->HandleLine(cur_line);
90 } else {
91 me->m_line_buffer += cur_line;
92 me->HandleLine(me->m_line_buffer);
93 me->m_line_buffer.clear();
94 }
95 str_data = str_data.substr(end_line + 1);
96 }
97 me->m_line_buffer = str_data;
98
99 return size * nitems;
100 }
101
102 void
103 CurlCopyOp::HandleLine(std::string_view line)
104 {
105 if (line == "Perf Marker") {
106 m_bytemark = -1;
107 } else if (line == "End") {
108 if (m_bytemark > -1 && m_callback) {
109 m_callback->Progress(m_bytemark);
110 }
111 } else {
112 auto key_end_pos = line.find(':');
113 if (key_end_pos == line.npos) {
114 return; // All the other callback lines should be of key: value format
115 }
116 auto key = line.substr(0, key_end_pos);
117 auto value = ltrim_view(line.substr(key_end_pos + 1));
118 if (key == "Stripe Bytes Transferred") {
119 try {
120 m_bytemark = std::stoll(std::string(value));
121 } catch (...) {
122 // TODO: Log failure
123 }
124 } else if (key == "success") {
125 m_sent_success = true;
126 } else if (key == "failure") {
127 m_failure = value;
128 }
129 }
130 }
131
void CURL
void Success() override
std::vector< std::pair< std::string, std::string > > Headers
void ReleaseHandle() override
CurlCopyOp(XrdCl::ResponseHandler *handler, const std::string &source_url, const Headers &source_hdrs, const std::string &dest_url, const Headers &dest_hdrs, struct timespec timeout, XrdCl::Log *logger, CreateConnCalloutType callout)
bool Setup(CURL *curl, CurlWorker &) override
void SetDone(bool has_failed)
std::unique_ptr< CURL, void(*)(CURL *)> m_curl
virtual void ReleaseHandle()
void UpdateBytes(uint64_t bytes)
std::vector< std::pair< std::string, std::string > > m_headers_list
XrdCl::ResponseHandler * m_handler
CurlOperation(XrdCl::ResponseHandler *handler, const std::string &url, struct timespec timeout, XrdCl::Log *log, CreateConnCalloutType, HeaderCallout *header_callout)
virtual bool Setup(CURL *curl, CurlWorker &)
Handle diagnostics.
Definition XrdClLog.hh:101
Handle an async response.
ConnectionCallout *(*)(const std::string &, const ResponseInfo &) CreateConnCalloutType
std::string_view ltrim_view(const std::string_view &input_view)