XRootD
TPC::State Class Reference

#include <XrdHttpTpcState.hh>

+ Collaboration diagram for TPC::State:

Public Member Functions

 State ()
 
 State (CURL *curl, bool tpcForwardCreds)
 
 State (off_t start_offset, Stream &stream, CURL *curl, bool push, bool tpcForwardCreds)
 
 ~State ()
 
int AvailableBuffers () const
 
bool BodyTransferInProgress () const
 
off_t BytesTransferred () const
 
void DumpBuffers () const
 
StateDuplicate ()
 
bool Finalize ()
 
int Flush ()
 
std::string GetConnectionDescription ()
 
off_t GetContentLength () const
 
int GetErrorCode () const
 
std::string GetErrorMessage () const
 
CURLGetHandle () const
 
int GetStatusCode () const
 
void Move (State &other)
 
void ResetAfterRequest ()
 
void SetContentLength (const off_t content_length)
 
void SetErrorCode (int error_code)
 
void SetErrorMessage (const std::string &error_msg)
 
void SetTransferParameters (off_t offset, size_t size)
 
void SetupHeaders (XrdHttpExtReq &req)
 

Detailed Description

Definition at line 21 of file XrdHttpTpcState.hh.

Constructor & Destructor Documentation

◆ State() [1/3]

TPC::State::State ( )
inline

Definition at line 24 of file XrdHttpTpcState.hh.

24  :
25  m_push(true),
26  m_recv_status_line(false),
27  m_recv_all_headers(false),
28  m_offset(0),
29  m_start_offset(0),
30  m_status_code(-1),
31  m_error_code(0),
32  m_content_length(-1),
33  m_stream(NULL),
34  m_curl(NULL),
35  m_headers(NULL),
36  m_is_transfer_state(true)
37  {}

Referenced by Duplicate().

+ Here is the caller graph for this function:

◆ State() [2/3]

TPC::State::State ( CURL curl,
bool  tpcForwardCreds 
)
inline

Don't use that constructor if you want to do some transfers.

Parameters
curlthe curl handle

Definition at line 43 of file XrdHttpTpcState.hh.

43  :
44  m_push(true),
45  m_recv_status_line(false),
46  m_recv_all_headers(false),
47  m_offset(0),
48  m_start_offset(0),
49  m_status_code(-1),
50  m_error_code(0),
51  m_content_length(-1),
52  m_push_length(-1),
53  m_stream(NULL),
54  m_curl(curl),
55  m_headers(NULL),
56  m_is_transfer_state(false),
57  tpcForwardCreds(tpcForwardCreds)
58  {
59  InstallHandlers(curl);
60  }

◆ State() [3/3]

TPC::State::State ( off_t  start_offset,
Stream stream,
CURL curl,
bool  push,
bool  tpcForwardCreds 
)
inline

Definition at line 65 of file XrdHttpTpcState.hh.

65  :
66  m_push(push),
67  m_recv_status_line(false),
68  m_recv_all_headers(false),
69  m_offset(0),
70  m_start_offset(start_offset),
71  m_status_code(-1),
72  m_error_code(0),
73  m_content_length(-1),
74  m_push_length(-1),
75  m_stream(&stream),
76  m_curl(curl),
77  m_headers(NULL),
78  m_is_transfer_state(true),
79  tpcForwardCreds(tpcForwardCreds)
80  {
81  InstallHandlers(curl);
82  }

◆ ~State()

State::~State ( )

Definition at line 18 of file XrdHttpTpcState.cc.

18  {
19  if (m_headers) {
20  curl_slist_free_all(m_headers);
21  m_headers = NULL;
22  if (m_curl) {curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_headers);}
23  }
24 }

Member Function Documentation

◆ AvailableBuffers()

int State::AvailableBuffers ( ) const

Definition at line 292 of file XrdHttpTpcState.cc.

293 {
294  return m_stream->AvailableBuffers();
295 }
size_t AvailableBuffers() const

References TPC::Stream::AvailableBuffers().

+ Here is the call graph for this function:

◆ BodyTransferInProgress()

bool TPC::State::BodyTransferInProgress ( ) const
inline

Definition at line 116 of file XrdHttpTpcState.hh.

116 {return m_offset && (m_offset != m_content_length);}

◆ BytesTransferred()

off_t TPC::State::BytesTransferred ( ) const
inline

Definition at line 90 of file XrdHttpTpcState.hh.

90 {return m_offset;}

◆ DumpBuffers()

void State::DumpBuffers ( ) const

Definition at line 297 of file XrdHttpTpcState.cc.

298 {
299  m_stream->DumpBuffers();
300 }
void DumpBuffers() const

References TPC::Stream::DumpBuffers().

+ Here is the call graph for this function:

◆ Duplicate()

State * State::Duplicate ( )

Definition at line 260 of file XrdHttpTpcState.cc.

260  {
261  CURL *curl = curl_easy_duphandle(m_curl);
262  if (!curl) {
263  throw std::runtime_error("Failed to duplicate existing curl handle.");
264  }
265 
266  State *state = new State(0, *m_stream, curl, m_push, tpcForwardCreds);
267 
268  if (m_headers) {
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();
272  header_iter++) {
273  state->m_headers = curl_slist_append(state->m_headers, header_iter->c_str());
274  state->m_headers_copy.push_back(*header_iter);
275  }
276  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
277  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, state->m_headers);
278  }
279 
280  return state;
281 }
void CURL

References State().

+ Here is the call graph for this function:

◆ Finalize()

bool State::Finalize ( )

Definition at line 302 of file XrdHttpTpcState.cc.

303 {
304  if (!m_stream->Finalize()) {
305  m_error_buf = m_stream->GetErrorMessage();
306  m_error_code = 3;
307  return false;
308  }
309  return true;
310 }
std::string GetErrorMessage() const

References TPC::Stream::Finalize(), and TPC::Stream::GetErrorMessage().

+ Here is the call graph for this function:

◆ Flush()

int State::Flush ( )

Definition at line 228 of file XrdHttpTpcState.cc.

228  {
229  if (m_push) {
230  return 0;
231  }
232 
233  ssize_t retval = m_stream->Write(m_start_offset + m_offset, 0, 0, true);
234  if (retval == SFS_ERROR) {
235  m_error_buf = m_stream->GetErrorMessage();
236  m_error_code = 2;
237  return -1;
238  }
239  m_offset += retval;
240  return retval;
241 }
#define SFS_ERROR
ssize_t Write(off_t offset, const char *buffer, size_t size, bool force)

References TPC::Stream::GetErrorMessage(), SFS_ERROR, and TPC::Stream::Write().

+ Here is the call graph for this function:

◆ GetConnectionDescription()

std::string State::GetConnectionDescription ( )

Definition at line 312 of file XrdHttpTpcState.cc.

313 {
314  // CURLINFO_PRIMARY_PORT is only defined for 7.21.0 or later; on older
315  // library versions, simply omit this information.
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) {
320  return "";
321  }
322  long curl_port = 0;
323  rc = curl_easy_getinfo(m_curl, CURLINFO_PRIMARY_PORT, &curl_port);
324  if ((rc != CURLE_OK) || !curl_port) {
325  return "";
326  }
327  std::stringstream ss;
328  // libcurl returns IPv6 addresses of the form:
329  // 2600:900:6:1301:5054:ff:fe0b:9cba:8000
330  // However the HTTP-TPC spec says to use the form
331  // [2600:900:6:1301:5054:ff:fe0b:9cba]:8000
332  // Hence, we add '[' and ']' whenever a ':' is seen.
333  if (NULL == strchr(curl_ip, ':'))
334  ss << "tcp:" << curl_ip << ":" << curl_port;
335  else
336  ss << "tcp:[" << curl_ip << "]:" << curl_port;
337  return ss.str();
338 #else
339  return "";
340 #endif
341 }

◆ GetContentLength()

off_t TPC::State::GetContentLength ( ) const
inline

Definition at line 94 of file XrdHttpTpcState.hh.

94 {return m_content_length;}

◆ GetErrorCode()

int TPC::State::GetErrorCode ( ) const
inline

Definition at line 96 of file XrdHttpTpcState.hh.

96 {return m_error_code;}

◆ GetErrorMessage()

std::string TPC::State::GetErrorMessage ( ) const
inline

Definition at line 102 of file XrdHttpTpcState.hh.

102 {return m_error_buf;}

◆ GetHandle()

CURL* TPC::State::GetHandle ( ) const
inline

Definition at line 108 of file XrdHttpTpcState.hh.

108 {return m_curl;}

◆ GetStatusCode()

int TPC::State::GetStatusCode ( ) const
inline

Definition at line 100 of file XrdHttpTpcState.hh.

100 {return m_status_code;}

◆ Move()

void State::Move ( State other)

Definition at line 27 of file XrdHttpTpcState.cc.

28 {
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) {
45  if (m_push) {
46  curl_easy_setopt(m_curl, CURLOPT_READDATA, this);
47  } else {
48  curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);
49  }
50  }
51  tpcForwardCreds = other.tpcForwardCreds;
52  other.m_headers_copy.clear();
53  other.m_curl = NULL;
54  other.m_headers = NULL;
55  other.m_stream = NULL;
56 }

◆ ResetAfterRequest()

void State::ResetAfterRequest ( )

Definition at line 135 of file XrdHttpTpcState.cc.

135  {
136  m_offset = 0;
137  m_status_code = -1;
138  m_content_length = -1;
139  m_push_length = -1;
140  m_recv_all_headers = false;
141  m_recv_status_line = false;
142 }

◆ SetContentLength()

void TPC::State::SetContentLength ( const off_t  content_length)
inline

Definition at line 92 of file XrdHttpTpcState.hh.

92 { m_content_length = content_length; }

◆ SetErrorCode()

void TPC::State::SetErrorCode ( int  error_code)
inline

Definition at line 98 of file XrdHttpTpcState.hh.

98 {m_error_code = error_code;}

◆ SetErrorMessage()

void TPC::State::SetErrorMessage ( const std::string &  error_msg)
inline

Definition at line 104 of file XrdHttpTpcState.hh.

104 {m_error_buf = error_msg;}

◆ SetTransferParameters()

void State::SetTransferParameters ( off_t  offset,
size_t  size 
)

Definition at line 283 of file XrdHttpTpcState.cc.

283  {
284  m_start_offset = offset;
285  m_offset = 0;
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());
290 }

◆ SetupHeaders()

void State::SetupHeaders ( XrdHttpExtReq req)

Setup any headers necessary for the GET/PUT operation

Currently includes:

  • Handle the 'Copy-Headers' feature
  • Adding Expect: 100-continue to get around a libcurl bug on uploads.

Definition at line 101 of file XrdHttpTpcState.cc.

101  {
102  struct curl_slist *list = NULL;
103  for (std::map<std::string, std::string>::const_iterator hdr_iter = req.headers.begin();
104  hdr_iter != req.headers.end();
105  hdr_iter++) {
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);
109  }
110  // Note: len("TransferHeader") == 14
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());
116  }
117  }
118 
119  if (m_is_transfer_state && m_push && m_push_length > 0) {
120  // On libcurl 8.5.0 - 8.9.1, we've observed bugs causing failures whenever
121  // `Expect: 100-continue` is not used. Older versions of libcurl unconditionally
122  // set `Expect` whenever PUT is used (likely an older bug). To workaround the issue,
123  // we force `Expect` to be set, triggering the older libcurl behavior.
124  // See: https://github.com/xrootd/xrootd/issues/2470
125  // See: https://github.com/curl/curl/issues/17004
126  list = curl_slist_append(list, "Expect: 100-continue");
127  }
128 
129  if (list != NULL) {
130  curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, list);
131  m_headers = list;
132  }
133 }
std::map< std::string, std::string > & headers

References XrdHttpExtReq::headers.


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