6 #include "XrdVersion.hh"
10 #include <curl/curl.h>
20 curl_slist_free_all(m_headers);
22 if (m_curl) {curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_headers);}
29 m_push = other.m_push;
30 m_recv_status_line = other.m_recv_status_line;
31 m_recv_all_headers = other.m_recv_all_headers;
32 m_offset = other.m_offset;
33 m_start_offset = other.m_start_offset;
34 m_status_code = other.m_status_code;
35 m_content_length = other.m_content_length;
36 m_push_length = other.m_push_length;
37 m_stream = other.m_stream;
38 m_curl = other.m_curl;
39 m_headers = other.m_headers;
40 m_headers_copy = other.m_headers_copy;
41 m_resp_protocol = other.m_resp_protocol;
42 m_is_transfer_state = other.m_is_transfer_state;
43 curl_easy_setopt(m_curl, CURLOPT_HEADERDATA,
this);
44 if (m_is_transfer_state) {
46 curl_easy_setopt(m_curl, CURLOPT_READDATA,
this);
48 curl_easy_setopt(m_curl, CURLOPT_WRITEDATA,
this);
51 tpcForwardCreds = other.tpcForwardCreds;
52 other.m_headers_copy.clear();
54 other.m_headers = NULL;
55 other.m_stream = NULL;
59 bool State::InstallHandlers(
CURL *curl) {
60 curl_easy_setopt(curl, CURLOPT_USERAGENT,
"xrootd-tpc/" XrdVERSION);
61 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &State::HeaderCB);
62 curl_easy_setopt(curl, CURLOPT_HEADERDATA,
this);
63 if(m_is_transfer_state) {
65 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
66 curl_easy_setopt(curl, CURLOPT_READFUNCTION, &State::ReadCB);
67 curl_easy_setopt(curl, CURLOPT_READDATA,
this);
70 m_push_length = buf.st_size;
71 curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, buf.st_size);
74 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &State::WriteCB);
75 curl_easy_setopt(curl, CURLOPT_WRITEDATA,
this);
78 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
80 curl_easy_setopt(curl,CURLOPT_UNRESTRICTED_AUTH,1L);
85 curl_version_info_data *curl_ver = curl_version_info(CURLVERSION_NOW);
86 if (curl_ver->age > 0 && curl_ver->version_num >= 0x072600) {
88 curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 2*60);
89 curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 10*1024);
102 struct curl_slist *list = NULL;
103 for (std::map<std::string, std::string>::const_iterator hdr_iter = req.
headers.begin();
106 if (!strcasecmp(hdr_iter->first.c_str(),
"copy-header")) {
107 list = curl_slist_append(list, hdr_iter->second.c_str());
108 m_headers_copy.emplace_back(hdr_iter->second);
111 if (!strncasecmp(hdr_iter->first.c_str(),
"transferheader",14)) {
112 std::stringstream ss;
113 ss << hdr_iter->first.substr(14) <<
": " << hdr_iter->second;
114 list = curl_slist_append(list, ss.str().c_str());
115 m_headers_copy.emplace_back(ss.str());
119 if (m_is_transfer_state && m_push && m_push_length > 0) {
126 list = curl_slist_append(list,
"Expect: 100-continue");
130 curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, list);
138 m_content_length = -1;
140 m_recv_all_headers =
false;
141 m_recv_status_line =
false;
144 size_t State::HeaderCB(
char *buffer,
size_t size,
size_t nitems,
void *userdata)
147 std::string header(buffer, size*nitems);
148 return obj->Header(header);
151 int State::Header(
const std::string &header) {
153 if (m_recv_all_headers) {
154 m_recv_all_headers =
false;
155 m_recv_status_line =
false;
157 if (!m_recv_status_line) {
158 std::stringstream ss(header);
161 m_resp_protocol = item;
165 m_status_code = std::stol(item);
169 m_recv_status_line =
true;
170 }
else if (header.size() == 0 || header ==
"\n" || header ==
"\r\n") {
171 m_recv_all_headers =
true;
173 else if (header !=
"\r\n") {
175 std::size_t found = header.find(
":");
176 if (found != std::string::npos) {
177 std::string header_name = header.substr(0, found);
178 std::transform(header_name.begin(), header_name.end(), header_name.begin(), ::tolower);
179 std::string header_value = header.substr(found+1);
180 if (header_name ==
"content-length")
183 m_content_length = std::stoll(header_value);
197 return header.size();
200 size_t State::WriteCB(
void *buffer,
size_t size,
size_t nitems,
void *userdata) {
206 obj->m_error_buf += std::string(
static_cast<char*
>(buffer),
207 std::min(
static_cast<size_t>(1024), size*nitems));
209 if (obj->m_error_buf.size() >= 1024)
214 return obj->Write(
static_cast<char*
>(buffer), size*nitems);
217 ssize_t State::Write(
char *buffer,
size_t size) {
218 ssize_t retval = m_stream->
Write(m_start_offset + m_offset, buffer, size,
false);
233 ssize_t retval = m_stream->
Write(m_start_offset + m_offset, 0, 0,
true);
243 size_t State::ReadCB(
void *buffer,
size_t size,
size_t nitems,
void *userdata) {
247 return obj->Read(
static_cast<char*
>(buffer), size*nitems);
250 int State::Read(
char *buffer,
size_t size) {
251 int retval = m_stream->
Read(m_start_offset + m_offset, buffer, size);
261 CURL *curl = curl_easy_duphandle(m_curl);
263 throw std::runtime_error(
"Failed to duplicate existing curl handle.");
266 State *state =
new State(0, *m_stream, curl, m_push, tpcForwardCreds);
269 state->m_headers_copy.reserve(m_headers_copy.size());
270 for (std::vector<std::string>::const_iterator header_iter = m_headers_copy.begin();
271 header_iter != m_headers_copy.end();
273 state->m_headers = curl_slist_append(state->m_headers, header_iter->c_str());
274 state->m_headers_copy.push_back(*header_iter);
276 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
277 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, state->m_headers);
284 m_start_offset = offset;
286 m_content_length = size;
287 std::stringstream ss;
288 ss << offset <<
"-" << (offset+size-1);
289 curl_easy_setopt(m_curl, CURLOPT_RANGE, ss.str().c_str());
316 #if LIBCURL_VERSION_NUM >= 0x071500
317 char *curl_ip = NULL;
318 CURLcode rc = curl_easy_getinfo(m_curl, CURLINFO_PRIMARY_IP, &curl_ip);
319 if ((rc != CURLE_OK) || !curl_ip) {
323 rc = curl_easy_getinfo(m_curl, CURLINFO_PRIMARY_PORT, &curl_port);
324 if ((rc != CURLE_OK) || !curl_port) {
327 std::stringstream ss;
333 if (NULL == strchr(curl_ip,
':'))
334 ss <<
"tcp:" << curl_ip <<
":" << curl_port;
336 ss <<
"tcp:[" << curl_ip <<
"]:" << curl_port;
void getline(uchar *buff, int blen)
int GetStatusCode() const
void SetTransferParameters(off_t offset, size_t size)
std::string GetConnectionDescription()
void SetupHeaders(XrdHttpExtReq &req)
int AvailableBuffers() const
int Read(off_t offset, char *buffer, size_t size)
ssize_t Write(off_t offset, const char *buffer, size_t size, bool force)
std::string GetErrorMessage() const
size_t AvailableBuffers() const
std::map< std::string, std::string > & headers