XRootD
XrdHttpReq Class Reference

#include <XrdHttpReq.hh>

+ Inheritance diagram for XrdHttpReq:
+ Collaboration diagram for XrdHttpReq:

Public Types

enum  ReqType : int {
  rtUnset = -1 ,
  rtUnknown = 0 ,
  rtMalformed ,
  rtGET ,
  rtHEAD ,
  rtPUT ,
  rtOPTIONS ,
  rtPATCH ,
  rtDELETE ,
  rtPROPFIND ,
  rtMKCOL ,
  rtMOVE ,
  rtPOST ,
  rtCOPY ,
  rtCount
}
 These are the HTTP/DAV requests that we support. More...
 

Public Member Functions

 XrdHttpReq (XrdHttpProtocol *protinstance, const XrdHttpReadRangeHandler::Configuration &rcfg)
 
virtual ~XrdHttpReq ()
 
void addCgi (const std::string &key, const std::string &value)
 
void appendOpaque (XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
 
std::string buildPartialHdr (long long bytestart, long long byteend, long long filesize, char *token)
 Build a partial header for a multipart response. More...
 
std::string buildPartialHdrEnd (char *token)
 Build the closing part for a multipart response. More...
 
virtual bool Data (XrdXrootd::Bridge::Context &info, const struct iovec *iovP, int iovN, int iovL, bool final)
 
virtual bool Done (XrdXrootd::Bridge::Context &info)
 the result context More...
 
virtual bool Error (XrdXrootd::Bridge::Context &info, int ecode, const char *etext)
 
virtual int File (XrdXrootd::Bridge::Context &info, int dlen)
 
int getHttpStatusCode ()
 
int getInitialStatusCode ()
 
int parseBody (char *body, long long len)
 Parse the body of a request, assuming that it's XML and that it's entirely in memory. More...
 
int parseFirstLine (char *line, int len)
 Parse the first line of the header. More...
 
int parseLine (char *line, int len)
 Parse the header. More...
 
int ProcessHTTPReq ()
 
virtual bool Redir (XrdXrootd::Bridge::Context &info, int port, const char *hname)
 
int ReqReadV (const XrdHttpIOList &cl)
 Prepare the buffers for sending a readv request. More...
 
virtual void reset ()
 
void setHttpStatusCode (int code)
 
void setTransferStatusHeader (std::string &header)
 
const std::string & userAgent () const
 
- Public Member Functions inherited from XrdXrootd::Bridge::Result
 Result ()
 Constructor & Destructor. More...
 
virtual ~Result ()
 
virtual void Free (Bridge::Context &info, char *buffP, int buffL)
 
virtual bool Wait (Bridge::Context &info, int wtime, const char *wtext)
 
virtual Bridge::Result * WaitResp (Bridge::Context &info, int wtime, const char *wtext)
 

Public Attributes

std::map< std::string, std::string > allheaders
 
bool closeAfterError
 
int depth
 
std::string destination
 The destination field specified in the req. More...
 
long long etagval
 
std::string etext
 
char fhandle [4]
 
long filectime
 
long fileflags
 
long filemodtime
 
long long filesize
 
bool final
 true -> final result More...
 
bool fopened
 
std::string hdr2cgistr
 Additional opaque info that may come from the hdr2cgi directive. More...
 
bool headerok
 Tells if we have finished reading the header. More...
 
std::string host
 The host field specified in the req. More...
 
int iovL
 byte count More...
 
int iovN
 array count More...
 
const struct iovec * iovP
 The latest data chunks got from the xrd layer. These are valid only inside the callbacks! More...
 
bool keepalive
 
ssize_t length
 
bool length_seen {false}
 
bool m_appended_asize {false}
 Track whether we already appended the oss.asize argument for PUTs. More...
 
bool m_appended_hdr2cgistr
 
std::string m_digest_header
 The computed digest for the HTTP response header. More...
 
std::string m_origin
 
std::map< std::string, std::string > m_repr_digest
 Repr-Digest map where the key is the digest name and the value is the base64 encoded digest value. More...
 
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum = nullptr
 The checksum that was ran for this request. More...
 
XrdOucString m_resource_with_digest
 
std::string m_want_digest
 The requested digest type. More...
 
std::map< std::string, uint8_t > m_want_repr_digest
 
XrdHttpMonState monState
 
int mScitag
 
XrdOucEnv * opaque
 The opaque data, after parsing. More...
 
std::vector< readahead_list > ralist
 
bool readClosing
 
XrdHttpReadRangeHandler readRangeHandler
 Tracking the next ranges of data to read during GET. More...
 
XrdOucString redirdest
 
int reqstate
 State machine to talk to the bridge. More...
 
ReqType request
 The request we got. More...
 
std::string requestverb
 
XrdOucString resource
 The resource specified by the request, stripped of opaque data. More...
 
XrdOucString resourceplusopaque
 The resource specified by the request, including all the opaque data. More...
 
unsigned int rwOpDone
 To coordinate multipart responses across multiple calls. More...
 
unsigned int rwOpPartialDone
 
bool sendcontinue
 
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::time_point::min()
 
std::string stringresp
 If we want to give a string as a response, we compose it here. More...
 
long long writtenbytes
 In a long write, we track where we have arrived. More...
 
XErrorCode xrderrcode
 
ClientRequest xrdreq
 The last issued xrd request, often pending. More...
 
XResponseType xrdresp
 The last response data we got. More...
 

Detailed Description

Definition at line 66 of file XrdHttpReq.hh.

Member Enumeration Documentation

◆ ReqType

enum XrdHttpReq::ReqType : int

These are the HTTP/DAV requests that we support.

Enumerator
rtUnset 
rtUnknown 
rtMalformed 
rtGET 
rtHEAD 
rtPUT 
rtOPTIONS 
rtPATCH 
rtDELETE 
rtPROPFIND 
rtMKCOL 
rtMOVE 
rtPOST 
rtCOPY 
rtCount 

Definition at line 77 of file XrdHttpReq.hh.

77  : int {
78  rtUnset = -1,
79  rtUnknown = 0,
81  rtGET,
82  rtHEAD,
83  rtPUT,
84  rtOPTIONS,
85  rtPATCH,
86  rtDELETE,
87  rtPROPFIND,
88  rtMKCOL,
89  rtMOVE,
90  rtPOST,
91  rtCOPY,
92  rtCount
93  };

Constructor & Destructor Documentation

◆ XrdHttpReq()

XrdHttpReq::XrdHttpReq ( XrdHttpProtocol *  protinstance,
const XrdHttpReadRangeHandler::Configuration &  rcfg 
)
inline

Definition at line 208 of file XrdHttpReq.hh.

208  :
209  readRangeHandler(rcfg), closeAfterError(false), keepalive(true) {
210 
211  prot = protinstance;
212  length = 0;
213  //xmlbody = 0;
214  depth = 0;
215  opaque = 0;
216  writtenbytes = 0;
217  fopened = false;
218  headerok = false;
219  mScitag = -1;
220  };
bool keepalive
Definition: XrdHttpReq.hh:295
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:285
ssize_t length
Definition: XrdHttpReq.hh:296
bool closeAfterError
Definition: XrdHttpReq.hh:293
long long writtenbytes
In a long write, we track where we have arrived.
Definition: XrdHttpReq.hh:364
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:279
bool fopened
Definition: XrdHttpReq.hh:355
XrdHttpReadRangeHandler readRangeHandler
Tracking the next ranges of data to read during GET.
Definition: XrdHttpReq.hh:288

References depth, fopened, headerok, length, mScitag, opaque, and writtenbytes.

◆ ~XrdHttpReq()

XrdHttpReq::~XrdHttpReq ( )
virtual

Definition at line 112 of file XrdHttpReq.cc.

112  {
113  //if (xmlbody) xmlFreeDoc(xmlbody);
114 
115  reset();
116 }
virtual void reset()
Definition: XrdHttpReq.cc:2762

References reset().

+ Here is the call graph for this function:

Member Function Documentation

◆ addCgi()

void XrdHttpReq::addCgi ( const std::string &  key,
const std::string &  value 
)

Definition at line 823 of file XrdHttpReq.cc.

823  {
824  if (hdr2cgistr.length() > 0) {
825  hdr2cgistr.append("&");
826  }
827  hdr2cgistr.append(key);
828  hdr2cgistr.append("=");
829  hdr2cgistr.append(value);
830 }
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.
Definition: XrdHttpReq.hh:320

References hdr2cgistr.

Referenced by parseLine().

+ Here is the caller graph for this function:

◆ appendOpaque()

void XrdHttpReq::appendOpaque ( XrdOucString &  s,
XrdSecEntity *  secent,
char *  hash,
time_t  tnow 
)

Definition at line 715 of file XrdHttpReq.cc.

715  {
716 
717  int l = 0;
718  char * p = 0;
719  if (opaque)
720  p = opaque->Env(l);
721 
722  if (hdr2cgistr.empty() && (l < 2) && !hash) return;
723 
724  // this works in most cases, except if the url already contains the xrdhttp tokens
725  s = s + "?";
726  if (!hdr2cgistr.empty()) {
727  s += encode_opaque(hdr2cgistr).c_str();
728  }
729  if (p && (l > 1)) {
730  if (!hdr2cgistr.empty()) {
731  s = s + "&";
732  }
733  s = s + encode_opaque(p + 1).c_str();
734  }
735 
736  if (hash) {
737  if (l > 1) s += "&";
738  s += "xrdhttptk=";
739  s += hash;
740 
741  s += "&xrdhttptime=";
742  char buf[256];
743  sprintf(buf, "%lld", (long long) tnow);
744  s += buf;
745 
746  if (secent) {
747  if (secent->name) {
748  s += "&xrdhttpname=";
749  s += encode_str(secent->name).c_str();
750  }
751  }
752 
753  if (secent->vorg) {
754  s += "&xrdhttpvorg=";
755  s += encode_str(secent->vorg).c_str();
756  }
757 
758  if (secent->host) {
759  s += "&xrdhttphost=";
760  s += encode_str(secent->host).c_str();
761  }
762 
763  if (secent->moninfo) {
764  s += "&xrdhttpdn=";
765  s += encode_str(secent->moninfo).c_str();
766  }
767 
768  if (secent->role) {
769  s += "&xrdhttprole=";
770  s += encode_str(secent->role).c_str();
771  }
772 
773  if (secent->grps) {
774  s += "&xrdhttpgrps=";
775  s += encode_str(secent->grps).c_str();
776  }
777 
778  if (secent->endorsements) {
779  s += "&xrdhttpendorsements=";
780  s += encode_str(secent->endorsements).c_str();
781  }
782 
783  if (secent->credslen) {
784  s += "&xrdhttpcredslen=";
785  char buf[16];
786  sprintf(buf, "%d", secent->credslen);
787  s += encode_str(buf).c_str();
788  }
789 
790  if (secent->credslen) {
791  if (secent->creds) {
792  s += "&xrdhttpcreds=";
793  // Apparently this string might be not 0-terminated (!)
794  char *zerocreds = strndup(secent->creds, secent->credslen);
795  if (zerocreds) {
796  s += encode_str(zerocreds).c_str();
797  free(zerocreds);
798  }
799  }
800  }
801  }
802  }
std::string encode_opaque(const std::string &opaque)
std::string encode_str(const std::string &str)
char * Env(int &envlen)
Definition: XrdOucEnv.hh:48
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
int credslen
Length of the 'creds' data.
Definition: XrdSecEntity.hh:78
char * creds
Raw entity credentials or cert.
Definition: XrdSecEntity.hh:77
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
char * endorsements
Protocol specific endorsements.
Definition: XrdSecEntity.hh:75
char * moninfo
Information for monitoring.
Definition: XrdSecEntity.hh:76
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70

References XrdSecEntity::creds, XrdSecEntity::credslen, encode_opaque(), encode_str(), XrdSecEntity::endorsements, XrdOucEnv::Env(), XrdSecEntity::grps, hdr2cgistr, XrdSecEntity::host, XrdSecEntity::moninfo, XrdSecEntity::name, opaque, XrdSecEntity::role, and XrdSecEntity::vorg.

Referenced by XrdHttpProtocol::Process(), ProcessHTTPReq(), and Redir().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildPartialHdr()

std::string XrdHttpReq::buildPartialHdr ( long long  bytestart,
long long  byteend,
long long  filesize,
char *  token 
)

Build a partial header for a multipart response.

Definition at line 488 of file XrdHttpReq.cc.

488  {
489  std::ostringstream s;
490 
491  s << "\r\n--" << token << "\r\n";
492  s << "Content-type: text/plain; charset=UTF-8\r\n";
493  s << "Content-range: bytes " << bytestart << "-" << byteend << "/" << fsz << "\r\n\r\n";
494 
495  return s.str();
496 }

◆ buildPartialHdrEnd()

std::string XrdHttpReq::buildPartialHdrEnd ( char *  token)

Build the closing part for a multipart response.

Definition at line 498 of file XrdHttpReq.cc.

498  {
499  std::ostringstream s;
500 
501  s << "\r\n--" << token << "--\r\n";
502 
503  return s.str();
504 }

◆ Data()

bool XrdHttpReq::Data ( XrdXrootd::Bridge::Context &  info,
const struct iovec *  iovP,
int  iovN,
int  iovL,
bool  final 
)
virtual

Effect a client data response.

The Data() method is called when Run() resulted in a successful data response. The method should rewrite the data and send it to the client using the associated XrdLink object. As an example, 1) Result::Data(info, iovP, iovN, iovL) is called. 2) Inspect iovP, rewrite the data. 3) Send the response: info->linkP->Send(new_iovP, new_iovN, new_iovL); 4) Handle send errors and cleanup(e.g. deallocate storage). 5) Return, the exchange is now complete.

Parameters
infothe context associated with the result.
iovPa pointer to the iovec structure containing the xrootd data response about to be sent to the client. The request header is not included in the iovec structure. The elements of this structure must not be modified by the method.
iovNthe number of elements in the iovec structure array.
iovLtotal number of data bytes that would be sent to the client. This is simply the sum of all the lengths in the iovec.
finalTrue is this is the final result. Otherwise, this is a partial result (i.e. kXR_oksofar) and more data will result causing additional callbacks.
Returns
true continue normal processing. false terminate the bridge and close the link.
Parameters
infothe result context
iovPpointer to data array
iovNarray count
iovLbyte count
finaltrue -> final result

Implements XrdXrootd::Bridge::Result.

Definition at line 506 of file XrdHttpReq.cc.

512  {
513 
514  TRACE(REQ, " XrdHttpReq::Data! final=" << final);
515 
516  this->xrdresp = kXR_ok;
517  this->iovP = iovP_;
518  this->iovN = iovN_;
519  this->iovL = iovL_;
520  this->final = final_;
521 
522  if (PostProcessHTTPReq(final_)) reset();
523 
524  return true;
525 
526 };
@ kXR_ok
Definition: XProtocol.hh:941
#define TRACE(act, x)
Definition: XrdTrace.hh:63
XResponseType xrdresp
The last response data we got.
Definition: XrdHttpReq.hh:337
int iovL
byte count
Definition: XrdHttpReq.hh:345
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
Definition: XrdHttpReq.hh:343
int iovN
array count
Definition: XrdHttpReq.hh:344

References iovL, iovN, iovP, kXR_ok, reset(), TRACE, and xrdresp.

+ Here is the call graph for this function:

◆ Done()

bool XrdHttpReq::Done ( XrdXrootd::Bridge::Context &  info)
virtual

the result context

Effect a client acknowledgement.

The Done() method is called when Run() resulted in success and there is no associated data for the client (equivalent to a simple kXR_ok response).

Parameters
infothe context associated with the result.
Returns
true continue normal processing. false terminate the bridge and close the link.

Implements XrdXrootd::Bridge::Result.

Definition at line 552 of file XrdHttpReq.cc.

552  {
553 
554  TRACE(REQ, " XrdHttpReq::Done");
555 
556  xrdresp = kXR_ok;
557 
558  this->iovN = 0;
559 
560  int r = PostProcessHTTPReq(true);
561  // Beware, we don't have to reset() if the result is 0
562  if (r) reset();
563  if (r < 0) return false;
564 
565 
566  return true;
567 };

References iovN, kXR_ok, reset(), TRACE, and xrdresp.

+ Here is the call graph for this function:

◆ Error()

bool XrdHttpReq::Error ( XrdXrootd::Bridge::Context &  info,
int  ecode,
const char *  etext 
)
virtual

Effect a client error response.

The Error() method is called when an error was encountered while processing the Run() request. The error should be reflected to the client.

Parameters
infothe context associated with the result.
ecodethe "kXR" error code describing the nature of the error. The code is in host byte format.
etexta null terminated string describing the error in human terms
Returns
true continue normal processing. false terminate the bridge and close the link.
Parameters
infothe result context
ecodethe "kXR" error code
etextassociated error message

Implements XrdXrootd::Bridge::Result.

Definition at line 569 of file XrdHttpReq.cc.

572  {
573 
574  TRACE(REQ, " XrdHttpReq::Error");
575 
576  xrdresp = kXR_error;
577  xrderrcode = (XErrorCode) ecode;
578 
579  if (etext_) {
580  char *s = escapeXML(etext_);
581  this->etext = s;
582  free(s);
583  }
584 
585  auto rc = PostProcessHTTPReq();
586  if (rc) {
587  reset();
588  }
589 
590  // If we are servicing a GET on a directory, it'll generate an error for the default
591  // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
592  // generate a directory listing (if configured).
593  if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
594  return true;
595 
596  return rc == 0;
597 };
XErrorCode
Definition: XProtocol.hh:1031
@ kXR_isDirectory
Definition: XProtocol.hh:1048
@ kXR_error
Definition: XProtocol.hh:945
struct ClientRequestHdr header
Definition: XProtocol.hh:887
kXR_unt16 requestid
Definition: XProtocol.hh:159
@ kXR_open
Definition: XProtocol.hh:123
char * escapeXML(const char *str)
std::string etext
Definition: XrdHttpReq.hh:339
ReqType request
The request we got.
Definition: XrdHttpReq.hh:269
XErrorCode xrderrcode
Definition: XrdHttpReq.hh:338
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:334

References escapeXML(), etext, ClientRequest::header, kXR_error, kXR_isDirectory, kXR_open, request, ClientRequestHdr::requestid, reset(), rtGET, TRACE, xrderrcode, xrdreq, and xrdresp.

+ Here is the call graph for this function:

◆ File()

int XrdHttpReq::File ( XrdXrootd::Bridge::Context &  info,
int  dlen 
)
virtual

Notify callback that a sendfile() request is pending.

The File() method is called when Run() resulted in a sendfile response (i.e. sendfile() would have been used to send data to the client). This allows the callback to reframe the sendfile() data using the Send() method in the passed context object (see class Context above).

Parameters
infothe context associated with the result.
dlentotal number of data bytes that would be sent to the client.
Returns
true continue normal processing. false terminate the bridge and close the link.
Parameters
infothe result context
dlenbyte count

Implements XrdXrootd::Bridge::Result.

Definition at line 528 of file XrdHttpReq.cc.

530  {
531 
532  // sendfile about to be sent by bridge for fetching data for GET:
533  // no https, no chunked+trailer, no multirange
534 
535  //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen);
536  int rc = info.Send(0, 0, 0, 0);
537  TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc);
538  bool start, finish;
539  // short read will be classed as error
540  if (rc) {
542  return false;
543  }
544 
545  if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
546  return false;
547 
548 
549  return true;
550 };
void NotifyError()
Force handler to enter error state.
int NotifyReadResult(const ssize_t ret, const UserRange **const urp, bool &start, bool &allend)
Advance internal counters concerning received bytes.
virtual int Send(const struct iovec *headP, int headN, const struct iovec *tailP, int tailN)

References XrdHttpReadRangeHandler::NotifyError(), XrdHttpReadRangeHandler::NotifyReadResult(), readRangeHandler, XrdXrootd::Bridge::Context::Send(), and TRACE.

+ Here is the call graph for this function:

◆ getHttpStatusCode()

int XrdHttpReq::getHttpStatusCode ( )
inline

Definition at line 227 of file XrdHttpReq.hh.

227 { return httpStatusCode;}

◆ getInitialStatusCode()

int XrdHttpReq::getInitialStatusCode ( )
inline

Definition at line 226 of file XrdHttpReq.hh.

226 { return initialStatusCode;}

◆ parseBody()

int XrdHttpReq::parseBody ( char *  body,
long long  len 
)

Parse the body of a request, assuming that it's XML and that it's entirely in memory.

Definition at line 96 of file XrdHttpReq.cc.

96  {
97  /*
98  * The document being in memory, it has no base per RFC 2396,
99  * and the "noname.xml" argument will serve as its base.
100  */
101  //xmlbody = xmlReadMemory(body, len, "noname.xml", NULL, 0);
102  //if (xmlbody == NULL) {
103  // fprintf(stderr, "Failed to parse document\n");
104  // return 1;
105  //}
106 
107 
108 
109  return 1;
110 }

Referenced by ProcessHTTPReq().

+ Here is the caller graph for this function:

◆ parseFirstLine()

int XrdHttpReq::parseFirstLine ( char *  line,
int  len 
)

Parse the first line of the header.

Definition at line 319 of file XrdHttpReq.cc.

319  {
320 
321  char *key = line;
322 
323  int pos;
324 
325  // Do the naive parsing
326  if (!line) return -1;
327 
328  // Look for the first space-delimited token
329  char *p = strchr((char *) line, (int) ' ');
330  if (!p) {
332  return -1;
333  }
334 
335 
336  pos = p - line;
337  // The first token cannot be too long
338  if (pos > MAX_TK_LEN - 1) {
340  return -2;
341  }
342 
343  // The first space-delimited char cannot be the first one
344  // this allows to deal with the case when a client sends a first line that starts with a space " GET / HTTP/1.1"
345  if(pos == 0) {
347  return -4;
348  }
349 
350  // the first token must be non empty
351  if (pos > 0) {
352  line[pos] = 0;
353  char *val = line + pos + 1;
354 
355  // Here we are supposed to initialize whatever flag or variable that is needed
356  // by looking at the first token of the line
357 
358  // The token is key
359  // The remainder is val, look for the resource
360  p = strchr((char *) val, (int) ' ');
361 
362  if (!p) {
364  line[pos] = ' ';
365  return -3;
366  }
367 
368  *p = '\0';
369  parseResource(val);
370 
371  *p = ' ';
372 
373  // Xlate the known header lines
374  if (!strcmp(key, "GET")) {
375  request = rtGET;
376  } else if (!strcmp(key, "HEAD")) {
377  request = rtHEAD;
378  } else if (!strcmp(key, "PUT")) {
379  request = rtPUT;
380  } else if (!strcmp(key, "POST")) {
381  request = rtPOST;
382  } else if (!strcmp(key, "PATCH")) {
383  request = rtPATCH;
384  } else if (!strcmp(key, "OPTIONS")) {
385  request = rtOPTIONS;
386  } else if (!strcmp(key, "DELETE")) {
387  request = rtDELETE;
388  } else if (!strcmp(key, "PROPFIND")) {
390  } else if (!strcmp(key, "MKCOL")) {
391  request = rtMKCOL;
392  } else if (!strcmp(key, "MOVE")) {
393  request = rtMOVE;
394  } else if (!strcmp(key, "COPY")) {
395  request = rtCOPY;
396  } else {
397  request = rtUnknown;
398  }
399 
400  requestverb = key;
401 
402  // The last token should be the protocol. If it is HTTP/1.0, then
403  // keepalive is disabled by default.
404  if (!strcmp(p+1, "HTTP/1.0\r\n")) {
405  keepalive = false;
406  }
407  line[pos] = ' ';
408  }
409 
410  return 0;
411 }
#define MAX_TK_LEN
Definition: XrdHttpReq.cc:67
std::string requestverb
Definition: XrdHttpReq.hh:270

References keepalive, MAX_TK_LEN, request, requestverb, rtCOPY, rtDELETE, rtGET, rtHEAD, rtMalformed, rtMKCOL, rtMOVE, rtOPTIONS, rtPATCH, rtPOST, rtPROPFIND, rtPUT, and rtUnknown.

Referenced by XrdHttpProtocol::Process().

+ Here is the caller graph for this function:

◆ parseLine()

int XrdHttpReq::parseLine ( char *  line,
int  len 
)

Parse the header.

Definition at line 118 of file XrdHttpReq.cc.

118  {
119 
120  char *key = line;
121  int pos;
122 
123  // Do the parsing
124  if (!line) return -1;
125 
126 
127  char *p = strchr((char *) line, (int) ':');
128  if (!p) {
129 
131  return -1;
132  }
133 
134  pos = (p - line);
135  if (pos > (MAX_TK_LEN - 1)) {
136 
138  return -2;
139  }
140 
141  if (pos > 0) {
142  line[pos] = 0;
143  char *val = line + pos + 1;
144 
145  // Trim left
146  while ( (!isgraph(*val) || (!*val)) && (val < line+len)) val++;
147 
148  // We memorize the headers also as a string
149  // because external plugins may need to process it differently
150  std::string ss = val;
151  if(ss.length() >= 2 && ss.substr(ss.length() - 2, 2) != "\r\n") {
153  return -3;
154  }
155  trim(ss);
156  allheaders[key] = ss;
157 
158  // Here we are supposed to initialize whatever flag or variable that is needed
159  // by looking at the first token of the line
160  // The token is key
161  // The value is val
162 
163  // Screen out the needed header lines
164  if (!strcasecmp(key, "connection")) {
165 
166  if (!strcasecmp(val, "Keep-Alive\r\n")) {
167  keepalive = true;
168  } else if (!strcasecmp(val, "close\r\n")) {
169  keepalive = false;
170  }
171 
172  } else if (!strcasecmp(key, "host")) {
173  parseHost(val);
174  } else if (!strcasecmp(key, "range")) {
175  // (rfc2616 14.35.1) says if Range header contains any range
176  // which is syntactically invalid the Range header should be ignored.
177  // Therefore no need for the range handler to report an error.
179  } else if (!strcasecmp(key, "content-length")) {
180  // Parse and validate the Content-Length value (one-or-more digits,
181  // no sign, no embedded garbage, no overflow). Anything malformed
182  // gives the server an ambiguous body length and is an HTTP request
183  // smuggling primitive — reject with HTTP 400.
184  // Reference: RFC 9112 §6.2, RFC 7230 §3.3.3 rule 4.
185  ssize_t parsed = XrdHttpHeaderUtils::parseContentLength(val);
186  if (parsed < 0) {
188  return -6;
189  }
190  if (m_transfer_encoding_chunked) {
191  // A request that already declared Transfer-Encoding: chunked and
192  // now also sends Content-Length is the classic smuggling vector
193  // (the frontend and backend may disagree on which header wins).
194  // Reference: RFC 9112 §6.1.
196  return -8;
197  }
198  if (length_seen && parsed != length) {
199  // Two Content-Length headers with different values. The body
200  // length is ambiguous; reject.
201  // Reference: RFC 7230 §3.3.3 rule 4.
203  return -7;
204  }
205  length = parsed;
206  length_seen = true;
207 
208  } else if (!strcasecmp(key, "destination")) {
209  destination.assign(val, line+len-val);
210  trim(destination);
211  } else if (!strcasecmp(key, "want-digest")) {
212  // Discard Want-Repr-Digest in favor of Want-Digest
213  m_want_repr_digest.clear();
214  m_want_digest.assign(val, line + len - val);
216  //Transform the user requests' want-digest to lowercase
217  std::transform(m_want_digest.begin(), m_want_digest.end(), m_want_digest.begin(), ::tolower);
218  } else if (!strcasecmp(key, "depth")) {
219  depth = -1;
220  if (strcmp(val, "infinity"))
221  depth = atoll(val);
222 
223  } else if (!strcasecmp(key, "expect") && strstr(val, "100-continue")) {
224  sendcontinue = true;
225  } else if (!strcasecmp(key, "te") && strstr(val, "trailers")) {
226  m_trailer_headers = true;
227  } else if (!strcasecmp(key, "transfer-encoding")) {
228  // Tokenize the Transfer-Encoding list and verify that "chunked"
229  // is present AND is the final encoding. Anything else (substring
230  // matches like "chunkedX", a non-final "chunked", or only unknown
231  // codings) is rejected so a frontend proxy cannot disagree with us
232  // about how the body is framed.
233  // Reference: RFC 9112 §6.1, RFC 7230 §3.3.1.
236  return -4;
237  }
238  if (length_seen) {
239  // Content-Length was already accepted and now Transfer-Encoding:
240  // chunked arrives. Reject (see the matching check in the
241  // Content-Length branch above).
242  // Reference: RFC 9112 §6.1.
244  return -8;
245  }
246  m_transfer_encoding_chunked = true;
247  } else if (!strcasecmp(key, "x-transfer-status") && strstr(val, "true")) {
248  m_transfer_encoding_chunked = true;
249  m_status_trailer = true;
250  } else if (!strcasecmp(key, "scitag")) {
251  if(prot->pmarkHandle != nullptr) {
252  parseScitag(val);
253  }
254  } else if (!strcasecmp(key, "user-agent")) {
255  m_user_agent = val;
256  trim(m_user_agent);
257  } else if (!strcasecmp(key,"origin")) {
258  m_origin = val;
259  trim(m_origin);
260  } else if (!strcasecmp(key,"repr-digest")) {
262  } else if (!strcasecmp(key,"want-repr-digest")) {
263  if(m_want_digest.empty()) {
264  // If Want-Digest was set, don't parse want-repr-digest
266  }
267  } else {
268  // Some headers need to be translated into "local" cgi info.
269  auto it = std::find_if(prot->hdr2cgimap.begin(), prot->hdr2cgimap.end(),[key](const auto & item) {
270  return !strcasecmp(key,item.first.c_str());
271  });
272  if (it != prot->hdr2cgimap.end() && (opaque ? (0 == opaque->Get(it->second.c_str())) : true)) {
273  std::string s;
274  s.assign(val, line+len-val);
275  trim(s);
276  addCgi(it->second,s);
277  }
278  }
279 
280 
281  line[pos] = ':';
282  }
283 
284  return 0;
285 }
void trim(std::string &str)
Definition: XrdHttpReq.cc:78
static int parseTransferEncoding(const std::string &value)
static void parseWantReprDigest(const std::string &value, std::map< std::string, uint8_t > &output)
static void parseReprDigest(const std::string &value, std::map< std::string, std::string > &output)
static ssize_t parseContentLength(const std::string &value)
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
void ParseContentRange(const char *const line)
parse the line after a "Range: " http request header
std::string destination
The destination field specified in the req.
Definition: XrdHttpReq.hh:304
std::map< std::string, uint8_t > m_want_repr_digest
Definition: XrdHttpReq.hh:377
std::map< std::string, std::string > m_repr_digest
Repr-Digest map where the key is the digest name and the value is the base64 encoded digest value.
Definition: XrdHttpReq.hh:373
bool length_seen
Definition: XrdHttpReq.hh:297
std::string m_origin
Definition: XrdHttpReq.hh:368
std::string m_want_digest
The requested digest type.
Definition: XrdHttpReq.hh:307
std::map< std::string, std::string > allheaders
Definition: XrdHttpReq.hh:274
void addCgi(const std::string &key, const std::string &value)
Definition: XrdHttpReq.cc:823
bool sendcontinue
Definition: XrdHttpReq.hh:299
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69

References addCgi(), allheaders, depth, destination, XrdOucEnv::Get(), XrdHttpProtocol::hdr2cgimap, keepalive, length, length_seen, m_origin, m_repr_digest, m_want_digest, m_want_repr_digest, MAX_TK_LEN, opaque, XrdHttpHeaderUtils::parseContentLength(), XrdHttpReadRangeHandler::ParseContentRange(), XrdHttpHeaderUtils::parseReprDigest(), XrdHttpHeaderUtils::parseTransferEncoding(), XrdHttpHeaderUtils::parseWantReprDigest(), XrdHttpProtocol::pmarkHandle, readRangeHandler, request, rtMalformed, sendcontinue, and trim().

Referenced by XrdHttpProtocol::Process().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ProcessHTTPReq()

int XrdHttpReq::ProcessHTTPReq ( )

Crunch an http request. Return values: 0->call Process again 1->request processed -1->error

If we have to add extra header information, add it here.

Definition at line 927 of file XrdHttpReq.cc.

927  {
928 
929  kXR_int32 l;
930  if (startTime == std::chrono::steady_clock::time_point::min()) startTime = std::chrono::steady_clock::now();
931 
932  // State variable for tracking the query parameter search
933  // - 0: Indicates we've not yet searched the URL for '?'
934  // - 1: Indicates we have a '?' and hence query parameters
935  // - 2: Indicates we do *not* have '?' present -- no query parameters
936  int query_param_status = 0;
937  if (!m_appended_asize) {
938  m_appended_asize = true;
939  if (request == rtPUT && length) {
940  if (query_param_status == 0) {
941  query_param_status = strchr(resourceplusopaque.c_str(), '?') ? 1 : 2;
942  }
943  resourceplusopaque.append((query_param_status == 1) ? '&' : '?');
944  query_param_status = 1;
945  auto length_str = std::to_string(length);
946  resourceplusopaque.append("oss.asize=");
947  resourceplusopaque.append(length_str.c_str());
948  if (!opaque) {
949  opaque = new XrdOucEnv();
950  }
951  opaque->Put("oss.asize", length_str.c_str());
952  }
953  }
954 
956  if (!m_appended_hdr2cgistr && !hdr2cgistr.empty()) {
957  if (query_param_status == 0) {
958  query_param_status = strchr(resourceplusopaque.c_str(), '?') ? 1 : 2;
959  }
960  resourceplusopaque.append((query_param_status == 1) ? '&' : '?');
961 
962  std::string hdr2cgistrEncoded = encode_opaque(hdr2cgistr);
963  resourceplusopaque.append(hdr2cgistrEncoded.c_str());
964  if (TRACING(TRACE_DEBUG)) {
965  // The obfuscation of "authz" will only be done if the server http.header2cgi config contains something that maps a header to this "authz" cgi.
966  // Unfortunately the obfuscation code will be called no matter what is configured in http.header2cgi.
967  std::string header2cgistrObf = obfuscateAuth(hdr2cgistr);
968 
969  TRACEI(DEBUG, "Appended header fields to opaque info: '"
970  << header2cgistrObf.c_str() << "'");
971 
972  }
973 
974  m_appended_hdr2cgistr = true;
975  }
976 
977  // Verify if we have an external handler for this request
978  if (reqstate == 0) {
979  XrdHttpExtHandler *exthandler = prot->FindMatchingExtHandler(*this);
980  if (exthandler) {
981  XrdHttpExtReq xreq(this, prot);
982  int r = exthandler->ProcessReq(xreq);
983  reset();
984  if (!r) return 1; // All went fine, response sent
985  if (r < 0) return -1; // There was a hard error... close the connection
986 
987  return 1; // There was an error and a response was sent
988  }
989  }
990 
991  //
992  // Here we process the request locally
993  //
994 
995  switch (request) {
996  case XrdHttpReq::rtUnset:
997  return -1;
1000  generateWebdavErrMsg();
1001  prot->SendSimpleResp(400, NULL, NULL, httpErrorBody.c_str(), httpErrorBody.length(), false);
1002  reset();
1003  return -1;
1004  }
1005  case XrdHttpReq::rtHEAD:
1006  {
1007  if (reqstate == 0) {
1008  // Always start with Stat; in the case of a checksum request, we'll have a follow-up query
1009  if (prot->doStat((char *) resourceplusopaque.c_str())) {
1010  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
1011  return -1;
1012  }
1013  return 0;
1014  } else {
1015  // Note that doChksum requires that the memory stays alive until the callback is invoked.
1016  int prepareCksum = prepareChecksumQuery(m_req_cksum, m_resource_with_digest);
1017  if(prepareCksum < 0) {
1018  return -1;
1019  }
1020  if (prot->doChksum(m_resource_with_digest) < 0) {
1021  // In this case, the Want-Digest header was set and PostProcess gave the go-ahead to do a checksum.
1022  prot->SendSimpleResp(500, NULL, NULL, (char *) "Failed to create initial checksum request.", 0, false);
1023  return -1;
1024  }
1025  return 1;
1026  }
1027  }
1028  case XrdHttpReq::rtGET:
1029  {
1030  int retval = keepalive ? 1 : -1; // reset() clears keepalive
1031 
1032  if (resource.beginswith("/static/")) {
1033 
1034  // This is a request for a /static resource
1035  // If we have to use the embedded ones then we return the ones in memory as constants
1036 
1037  // The sysadmin can always redirect the request to another host that
1038  // contains his static resources
1039 
1040  // We also allow xrootd to preread from the local disk all the files
1041  // that have to be served as static resources.
1042 
1043  if (prot->embeddedstatic) {
1044 
1045  // Default case: the icon and the css of the HTML rendering of XrdHttp
1046  if (resource == "/static/css/xrdhttp.css") {
1047  prot->SendSimpleResp(200, NULL, NULL, (char *) static_css_xrdhttp_css, static_css_xrdhttp_css_len, keepalive);
1048  reset();
1049  return retval;
1050  }
1051  if (resource == "/static/icons/xrdhttp.ico") {
1052  prot->SendSimpleResp(200, NULL, NULL, (char *) favicon_ico, favicon_ico_len, keepalive);
1053  reset();
1054  return retval;
1055  }
1056 
1057  }
1058 
1059  // If we are here then none of the embedded resources match (or they are disabled)
1060  // We may have to redirect to a host that is supposed to serve the static resources
1061  if (prot->staticredir) {
1062 
1063  XrdOucString s = "Location: ";
1064  s.append(prot->staticredir);
1065 
1066  if (s.endswith('/'))
1067  s.erasefromend(1);
1068 
1069  s.append(encode_str(std::string(resource.c_str())).c_str());
1070  appendOpaque(s, 0, 0, 0);
1071 
1072  prot->SendSimpleResp(302, NULL, (char *) s.c_str(), 0, 0, false);
1073  return -1;
1074 
1075 
1076  } else {
1077 
1078  // We lookup the requested path in a hash containing the preread files
1079  if (prot->staticpreload) {
1081  if (mydata) {
1082  prot->SendSimpleResp(200, NULL, NULL, (char *) mydata->data, mydata->len, keepalive);
1083  reset();
1084  return retval;
1085  }
1086  }
1087 
1088  }
1089 
1090 
1091  }
1092 
1093  // The reqstate parameter basically moves us through a simple state machine.
1094  // To optimize things, we start off by opening the file; if it turns out to be a directory, then
1095  // we close the file handle and switch to doing a HTML-based rendering of the directory. This
1096  // avoids needing to always to do "stat" first to determine the next step (since the file-open also
1097  // does a "stat").
1098  // - 0: Perform an open on the resource
1099  // - 1: Perform a checksum request on the resource (only if requested in header; otherwise skipped)
1100  // - 2: Perform a close (for dirlist only)
1101  // - 3: Perform a dirlist.
1102  // - 4+: Reads from file; if at end, perform a close.
1103  switch (reqstate) {
1104  case 0: // Open the path for reading.
1105  {
1106  memset(&xrdreq, 0, sizeof (ClientRequest));
1107  xrdreq.open.requestid = htons(kXR_open);
1108  l = resourceplusopaque.length() + 1;
1109  xrdreq.open.dlen = htonl(l);
1110  xrdreq.open.mode = 0;
1112 
1113  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1114  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
1115  return -1;
1116  }
1117 
1118  // Prepare to chunk up the request
1119  writtenbytes = 0;
1120 
1121  // We want to be invoked again after this request is finished
1122  return 0;
1123  }
1124  case 1: // Checksum request
1125  if (!(fileflags & kXR_isDir) && (!m_want_digest.empty() || !m_want_repr_digest.empty())) {
1126  // In this case, the Want-Digest or then Want-Repr-Digest header was set.
1127  int prepareCksum = prepareChecksumQuery(m_req_cksum, m_resource_with_digest);
1128  if(prepareCksum < 0) {
1129  return -1;
1130  }
1131  if (prot->doChksum(m_resource_with_digest) < 0) {
1132  prot->SendSimpleResp(500, NULL, NULL, (char *) "Failed to start internal checksum request to satisfy Want-Digest or Want-Repr-Digest header.", 0, false);
1133  return -1;
1134  }
1135  return 0;
1136  } else {
1137  TRACEI(DEBUG, "No checksum requested; skipping to request state 2");
1138  reqstate += 1;
1139  }
1140  // fallthrough
1141  case 2: // Close file handle for directory
1142  if ((fileflags & kXR_isDir) && fopened) {
1143  memset(&xrdreq, 0, sizeof (ClientRequest));
1144  xrdreq.close.requestid = htons(kXR_close);
1145  memcpy(xrdreq.close.fhandle, fhandle, 4);
1146 
1147  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1148  generateWebdavErrMsg();
1149  return sendFooterError("Could not run close request on the bridge");
1150  }
1151  return 0;
1152  } else {
1153  reqstate += 1;
1154  }
1155  // fallthrough
1156  case 3: // List directory
1157  if (fileflags & kXR_isDir) {
1158  if (prot->listdeny) {
1159  // Return 403 as the administrator forbid the directory listing
1160  prot->SendSimpleResp(403, NULL, NULL, (char *) "Listings are disabled.", 0, false);
1161  return -1;
1162  }
1163 
1164  if (prot->listredir) {
1165  XrdOucString s = "Location: ";
1166  s.append(prot->listredir);
1167 
1168  if (s.endswith('/'))
1169  s.erasefromend(1);
1170 
1171  s.append(encode_str(std::string(resource.c_str())).c_str());
1172  appendOpaque(s, 0, 0, 0);
1173 
1174  prot->SendSimpleResp(302, NULL, (char *) s.c_str(), 0, 0, false);
1175  return -1;
1176  }
1177 
1178  std::string res;
1179  res = resourceplusopaque.c_str();
1180 
1181  // --------- DIRLIST
1182  memset(&xrdreq, 0, sizeof (ClientRequest));
1185  l = res.length() + 1;
1186  xrdreq.dirlist.dlen = htonl(l);
1187 
1188  if (!prot->Bridge->Run((char *) &xrdreq, (char *) res.c_str(), l)) {
1189  generateWebdavErrMsg();
1190  prot->SendSimpleResp(httpStatusCode, NULL, NULL, httpErrorBody.c_str(), httpErrorBody.length(), false);
1191  sendFooterError("Could not run listing request on the bridge");
1192  return -1;
1193  }
1194 
1195  // We don't want to be invoked again after this request is finished
1196  return 1;
1197  }
1198  else {
1199  reqstate += 1;
1200  }
1201  // fallthrough
1202  case 4:
1203  {
1204  auto retval = ReturnGetHeaders();
1205  if (retval) {
1206  return retval;
1207  }
1208  }
1209  // fallthrough
1210  default: // Read() or Close(); reqstate is 4+
1211  {
1212  const XrdHttpIOList &readChunkList = readRangeHandler.NextReadList();
1213 
1214  // Close() if we have finished, otherwise read the next chunk
1215 
1216  // --------- CLOSE
1217  if ( closeAfterError || readChunkList.empty() )
1218  {
1219 
1220  memset(&xrdreq, 0, sizeof (ClientRequest));
1221  xrdreq.close.requestid = htons(kXR_close);
1222  memcpy(xrdreq.close.fhandle, fhandle, 4);
1223 
1224  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1225  TRACEI(REQ, " Failed to run close request on the bridge.");
1226  // Note: we have already completed the request and sent the data to the client.
1227  // Hence, there's no need to send an error. However, since the bridge is potentially
1228  // in a bad state, we close the TCP socket to force the client to reconnect.
1229  return -1;
1230  }
1231 
1232  // We have finished
1233  readClosing = true;
1234  return 1;
1235 
1236  }
1237  // --------- READ or READV
1238 
1239  if ( readChunkList.size() == 1 ) {
1240  // Use a read request for single range
1241 
1242  long l;
1243  long long offs;
1244 
1245  // --------- READ
1246  memset(&xrdreq, 0, sizeof (xrdreq));
1247  xrdreq.read.requestid = htons(kXR_read);
1248  memcpy(xrdreq.read.fhandle, fhandle, 4);
1249  xrdreq.read.dlen = 0;
1250 
1251  offs = readChunkList[0].offset;
1252  l = readChunkList[0].size;
1253 
1254  xrdreq.read.offset = htonll(offs);
1255  xrdreq.read.rlen = htonl(l);
1256 
1257  // If we are using HTTPS or if the client requested trailers, or if the
1258  // read concerns a multirange reponse, disable sendfile
1259  // (in the latter two cases, the extra framing is only done in PostProcessHTTPReq)
1260  if (prot->ishttps || (m_transfer_encoding_chunked && m_trailer_headers) ||
1262  if (!prot->Bridge->setSF((kXR_char *) fhandle, false)) {
1263  TRACE(REQ, " XrdBridge::SetSF(false) failed.");
1264 
1265  }
1266  }
1267 
1268 
1269 
1270  if (l <= 0) {
1271  if (l < 0) {
1272  TRACE(ALL, " Data sizes mismatch.");
1273  return -1;
1274  }
1275  else {
1276  TRACE(ALL, " No more bytes to send.");
1277  reset();
1278  return 1;
1279  }
1280  }
1281 
1282  if ((offs >= filesize) || (offs+l > filesize)) {
1283  httpStatusCode = 416;
1284  httpErrorBody = "Range Not Satisfiable";
1285  std::stringstream ss;
1286  ss << "Requested range " << l << "@" << offs << " is past the end of file (" << filesize << ")";
1287  return sendFooterError(ss.str());
1288  }
1289 
1290  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1291  generateWebdavErrMsg();
1292  return sendFooterError("Could not run read request on the bridge");
1293  }
1294  } else {
1295  // --------- READV
1296 
1297  length = ReqReadV(readChunkList);
1298 
1299  if (!prot->Bridge->Run((char *) &xrdreq, (char *) &ralist[0], length)) {
1300  generateWebdavErrMsg();
1301  return sendFooterError("Could not run ReadV request on the bridge");
1302  }
1303 
1304  }
1305 
1306  // We want to be invoked again after this request is finished
1307  return 0;
1308  } // case 3+
1309 
1310  } // switch (reqstate)
1311 
1312 
1313  } // case XrdHttpReq::rtGET
1314 
1315  case XrdHttpReq::rtPUT:
1316  {
1317  //if (prot->ishttps) {
1318  //prot->SendSimpleResp(501, NULL, NULL, (char *) "HTTPS not supported yet for direct writing. Sorry.", 0);
1319  //return -1;
1320  //}
1321 
1322  if (!fopened) {
1323 
1324  // --------- OPEN for write!
1325  memset(&xrdreq, 0, sizeof (ClientRequest));
1326  xrdreq.open.requestid = htons(kXR_open);
1327  l = resourceplusopaque.length() + 1;
1328  xrdreq.open.dlen = htonl(l);
1329  xrdreq.open.mode = htons(kXR_ur | kXR_uw | kXR_gw | kXR_gr | kXR_or);
1330  // 'Overwrite: F' (e.g. forwarded by a TPC push) forbids replacing
1331  // an existing file; the open then fails with kXR_ItExists (409).
1332  auto overwrite = XrdOucTUtils::caseInsensitiveFind(allheaders, "overwrite");
1333  bool noOverwrite = overwrite != allheaders.end() && overwrite->second == "F";
1334  if (! XrdHttpProtocol::usingEC && ! noOverwrite)
1336  else
1338 
1339  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1340  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, keepalive);
1341  return -1;
1342  }
1343 
1344 
1345  // We want to be invoked again after this request is finished
1346  // Only if there is data to fetch from the socket or there will
1347  // never be more data
1348  if (prot->BuffUsed() > 0 || (length == 0 && !sendcontinue))
1349  return 0;
1350 
1351  return 1;
1352 
1353  } else {
1354 
1355  if (m_transfer_encoding_chunked) {
1356  if (m_current_chunk_size == m_current_chunk_offset) {
1357  // Chunk has been consumed; we now must process the CRLF.
1358  // Note that we don't support trailer headers.
1359  if (prot->BuffUsed() < 2) return 1;
1360  if (prot->myBuffStart[0] != '\r' || prot->myBuffStart[1] != '\n') {
1361  prot->SendSimpleResp(400, NULL, NULL, (char *) "Invalid trailing chunk encoding.", 0, keepalive);
1362  return -1;
1363  }
1364  prot->BuffConsume(2);
1365  if (m_current_chunk_size == 0) {
1366  // All data has been sent. Turn off chunk processing and
1367  // set the bytes written and length appropriately; on next callback,
1368  // we will hit the close() block below.
1369  m_transfer_encoding_chunked = false;
1370  length = writtenbytes;
1371  return ProcessHTTPReq();
1372  }
1373  m_current_chunk_size = -1;
1374  m_current_chunk_offset = 0;
1375  // If there is more data, we try to process the next chunk; otherwise, return
1376  if (!prot->BuffUsed()) return 1;
1377  }
1378  if (-1 == m_current_chunk_size) {
1379 
1380  // Parse out the next chunk size.
1381  long long idx = 0;
1382  bool found_newline = false;
1383  // Set a maximum size of chunk we will allow
1384  // Nginx sets this to "NGX_MAX_OFF_T_VALUE", which is 9223372036854775807 (a some crazy number)
1385  // We set it to 1TB, which is 1099511627776
1386  // This is to prevent a malicious client from sending a very large chunk size
1387  // or a malformed chunk request.
1388  // 1TB in base-16 is 0x40000000000, so only allow 11 characters, plus the CRLF
1389  long long max_chunk_size_chars = std::min(static_cast<long long>(prot->BuffUsed()), static_cast<long long>(13));
1390  for (; idx < max_chunk_size_chars; idx++) {
1391  if (prot->myBuffStart[idx] == '\n') {
1392  found_newline = true;
1393  break;
1394  }
1395  }
1396  // If we found a new line, but it is the first character in the buffer (no chunk length)
1397  // or if the previous character is not a CR.
1398  if (found_newline && ((idx == 0) || prot->myBuffStart[idx-1] != '\r')) {
1399  prot->SendSimpleResp(400, NULL, NULL, (char *)"Invalid chunked encoding", 0, false);
1400  TRACE(REQ, "XrdHTTP PUT: Sending invalid chunk encoding. Start of chunk should have had a length, followed by a CRLF.");
1401  return -1;
1402  }
1403  if (found_newline) {
1404  char *endptr = NULL;
1405  std::string line_contents(prot->myBuffStart, idx);
1406  long long chunk_contents = strtoll(line_contents.c_str(), &endptr, 16);
1407  // Chunk sizes can be followed by trailer information or CRLF
1408  if (*endptr != ';' && *endptr != '\r') {
1409  prot->SendSimpleResp(400, NULL, NULL, (char *)"Invalid chunked encoding", 0, false);
1410  TRACE(REQ, "XrdHTTP PUT: Sending invalid chunk encoding. Chunk size was not followed by a ';' or CR." << __LINE__);
1411  return -1;
1412  }
1413  m_current_chunk_size = chunk_contents;
1414  m_current_chunk_offset = 0;
1415  prot->BuffConsume(idx + 1);
1416  TRACE(REQ, "XrdHTTP PUT: next chunk from client will be " << m_current_chunk_size << " bytes");
1417  } else {
1418  // Need more data!
1419  return 1;
1420  }
1421  }
1422 
1423  if (m_current_chunk_size == 0) {
1424  // All data has been sent. Invoke this routine again immediately to process CRLF
1425  return ProcessHTTPReq();
1426  } else {
1427  // At this point, we have a chunk size defined and should consume payload data
1428  memset(&xrdreq, 0, sizeof (xrdreq));
1429  xrdreq.write.requestid = htons(kXR_write);
1430  memcpy(xrdreq.write.fhandle, fhandle, 4);
1431 
1432  long long chunk_bytes_remaining = m_current_chunk_size - m_current_chunk_offset;
1433  long long bytes_to_write = std::min(static_cast<long long>(prot->BuffUsed()),
1434  chunk_bytes_remaining);
1435 
1436  xrdreq.write.offset = htonll(writtenbytes);
1437  xrdreq.write.dlen = htonl(bytes_to_write);
1438 
1439  TRACEI(REQ, "XrdHTTP PUT: Writing chunk of size " << bytes_to_write << " starting with '" << *(prot->myBuffStart) << "'" << " with " << chunk_bytes_remaining << " bytes remaining in the chunk");
1440  if (!prot->Bridge->Run((char *) &xrdreq, prot->myBuffStart, bytes_to_write)) {
1441  generateWebdavErrMsg();
1442  return sendFooterError("Could not run write request on the bridge");
1443  }
1444  // If there are more bytes in the buffer, then immediately call us after the
1445  // write is finished; otherwise, wait for data.
1446  return (prot->BuffUsed() > chunk_bytes_remaining) ? 0 : 1;
1447  }
1448  } else if (writtenbytes < length) {
1449 
1450 
1451  // --------- WRITE
1452  memset(&xrdreq, 0, sizeof (xrdreq));
1453  xrdreq.write.requestid = htons(kXR_write);
1454  memcpy(xrdreq.write.fhandle, fhandle, 4);
1455 
1456  long long bytes_to_read = std::min(static_cast<long long>(prot->BuffUsed()),
1457  length - writtenbytes);
1458 
1459  xrdreq.write.offset = htonll(writtenbytes);
1460  xrdreq.write.dlen = htonl(bytes_to_read);
1461 
1462  TRACEI(REQ, "Writing " << bytes_to_read);
1463  if (!prot->Bridge->Run((char *) &xrdreq, prot->myBuffStart, bytes_to_read)) {
1464  generateWebdavErrMsg();
1465  return sendFooterError("Could not run write request on the bridge");
1466  }
1467 
1468  if (writtenbytes + prot->BuffUsed() >= length)
1469  // Trigger an immediate recall after this request has finished
1470  return 0;
1471  else
1472  // We want to be invoked again after this request is finished
1473  // only if there is pending data
1474  return 1;
1475 
1476 
1477 
1478  } else {
1479 
1480  // --------- CLOSE
1481  memset(&xrdreq, 0, sizeof (ClientRequest));
1482  xrdreq.close.requestid = htons(kXR_close);
1483  memcpy(xrdreq.close.fhandle, fhandle, 4);
1484 
1485 
1486  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1487  generateWebdavErrMsg();
1488  return sendFooterError("Could not run close request on the bridge");
1489  }
1490 
1491  // We have finished
1492  return 1;
1493 
1494  }
1495 
1496  }
1497 
1498  break;
1499 
1500  }
1501  case XrdHttpReq::rtOPTIONS:
1502  {
1503  prot->SendSimpleResp(200, NULL, (char *) "DAV: 1\r\nDAV: <http://apache.org/dav/propset/fs/1>\r\nAllow: HEAD,GET,PUT,PROPFIND,DELETE,OPTIONS", NULL, 0, keepalive);
1504  bool ret_keepalive = keepalive; // reset() clears keepalive
1505  reset();
1506  return ret_keepalive ? 1 : -1;
1507  }
1508  case XrdHttpReq::rtDELETE:
1509  {
1510 
1511 
1512  switch (reqstate) {
1513 
1514  case 0: // Stat()
1515  {
1516 
1517 
1518  // --------- STAT is always the first step
1519  memset(&xrdreq, 0, sizeof (ClientRequest));
1520  xrdreq.stat.requestid = htons(kXR_stat);
1521  std::string s = resourceplusopaque.c_str();
1522 
1523 
1524  l = resourceplusopaque.length() + 1;
1525  xrdreq.stat.dlen = htonl(l);
1526 
1527  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1528  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1529  return -1;
1530  }
1531 
1532  // We need to be invoked again to complete the request
1533  return 0;
1534  }
1535  default:
1536 
1537  if (fileflags & kXR_isDir) {
1538  // --------- RMDIR
1539  memset(&xrdreq, 0, sizeof (ClientRequest));
1540  xrdreq.rmdir.requestid = htons(kXR_rmdir);
1541 
1542  std::string s = resourceplusopaque.c_str();
1543 
1544  l = s.length() + 1;
1545  xrdreq.rmdir.dlen = htonl(l);
1546 
1547  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1548  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run rmdir request.", 0, false);
1549  return -1;
1550  }
1551  } else {
1552  // --------- DELETE
1553  memset(&xrdreq, 0, sizeof (ClientRequest));
1554  xrdreq.rm.requestid = htons(kXR_rm);
1555 
1556  std::string s = resourceplusopaque.c_str();
1557 
1558  l = s.length() + 1;
1559  xrdreq.rm.dlen = htonl(l);
1560 
1561  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1562  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run rm request.", 0, false);
1563  return -1;
1564  }
1565  }
1566 
1567 
1568  // We don't want to be invoked again after this request is finished
1569  return 1;
1570 
1571  }
1572 
1573 
1574 
1575  }
1576  case XrdHttpReq::rtPATCH:
1577  {
1578  prot->SendSimpleResp(501, NULL, NULL, (char *) "Request not supported yet.", 0, false);
1579 
1580  return -1;
1581  }
1583  {
1584 
1585 
1586 
1587  switch (reqstate) {
1588 
1589  case 0: // Stat() and add the current item to the list of the things to send
1590  {
1591 
1592  if (length > 0) {
1593  TRACE(REQ, "Reading request body " << length << " bytes.");
1594  char *p = 0;
1595  // We have to specifically read all the request body
1596 
1597  if (prot->BuffgetData(length, &p, true) < length) {
1598  prot->SendSimpleResp(501, NULL, NULL, (char *) "Error in getting the PROPFIND request body.", 0, false);
1599  return -1;
1600  }
1601 
1602  if ((depth > 1) || (depth < 0)) {
1603  prot->SendSimpleResp(501, NULL, NULL, (char *) "Invalid depth value.", 0, false);
1604  return -1;
1605  }
1606 
1607 
1608  parseBody(p, length);
1609  }
1610 
1611 
1612  // --------- STAT is always the first step
1613  memset(&xrdreq, 0, sizeof (ClientRequest));
1614  xrdreq.stat.requestid = htons(kXR_stat);
1615  std::string s = resourceplusopaque.c_str();
1616 
1617 
1618  l = resourceplusopaque.length() + 1;
1619  xrdreq.stat.dlen = htonl(l);
1620 
1621  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1622  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1623  return -1;
1624  }
1625 
1626 
1627  if (depth == 0) {
1628  // We don't need to be invoked again
1629  return 1;
1630  } else
1631  // We need to be invoked again to complete the request
1632  return 0;
1633 
1634 
1635 
1636  break;
1637  }
1638 
1639  default: // Dirlist()
1640  {
1641 
1642  // --------- DIRLIST
1643  memset(&xrdreq, 0, sizeof (ClientRequest));
1645 
1646  std::string s = resourceplusopaque.c_str();
1648  //s += "?xrd.dirstat=1";
1649 
1650  l = s.length() + 1;
1651  xrdreq.dirlist.dlen = htonl(l);
1652 
1653  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1654  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1655  return -1;
1656  }
1657 
1658  // We don't want to be invoked again after this request is finished
1659  return 1;
1660  }
1661  }
1662 
1663 
1664  break;
1665  }
1666  case XrdHttpReq::rtMKCOL:
1667  {
1668 
1669  // --------- MKDIR
1670  memset(&xrdreq, 0, sizeof (ClientRequest));
1671  xrdreq.mkdir.requestid = htons(kXR_mkdir);
1672 
1673  std::string s = resourceplusopaque.c_str();
1675 
1676  l = s.length() + 1;
1677  xrdreq.mkdir.dlen = htonl(l);
1678 
1679  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1680  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1681  return -1;
1682  }
1683 
1684  // We don't want to be invoked again after this request is finished
1685  return 1;
1686  }
1687  case XrdHttpReq::rtMOVE:
1688  {
1689  // Skip the protocol part of destination URL
1690  size_t skip = destination.find("://");
1691  skip = (skip == std::string::npos) ? 0 : skip + 3;
1692 
1693  // If we have a manager role, enforce source and destination are on the same host
1694  if (prot->myRole == kXR_isManager && destination.compare(skip, host.size(), host) != 0) {
1695  prot->SendSimpleResp(501, NULL, NULL, (char *) "Only in-place renaming is supported for MOVE.", 0, false);
1696  return -1;
1697  }
1698 
1699  // If needed, append opaque info from source onto destination
1700  int pos = resourceplusopaque.find("?");
1701  if (pos != STR_NPOS) {
1702  destination.append((destination.find("?") == std::string::npos) ? "?" : "&");
1703  destination.append(resourceplusopaque.c_str() + pos + 1);
1704  }
1705 
1706  size_t path_pos = destination.find('/', skip + 1);
1707 
1708  if (path_pos == std::string::npos) {
1709  prot->SendSimpleResp(400, NULL, NULL, (char *) "Cannot determine destination path", 0, false);
1710  return -1;
1711  }
1712 
1713  // Construct args to kXR_mv request (i.e. <src> + " " + <dst>)
1714  std::string mv_args = std::string(resourceplusopaque.c_str()) + " " + destination.substr(path_pos);
1715 
1716  l = mv_args.length() + 1;
1717 
1718  // Prepare and run kXR_mv request
1719  memset(&xrdreq, 0, sizeof (ClientRequest));
1720  xrdreq.mv.requestid = htons(kXR_mv);
1722  xrdreq.mv.dlen = htonl(l);
1723 
1724  if (!prot->Bridge->Run((char *) &xrdreq, (char *) mv_args.c_str(), l)) {
1725  prot->SendSimpleResp(500, NULL, NULL, (char *) "Could not run request.", 0, false);
1726  return -1;
1727  }
1728 
1729  // We don't want to be invoked again after this request is finished
1730  return 1;
1731  }
1732  default:
1733  {
1734  prot->SendSimpleResp(501, NULL, NULL, (char *) "Request not supported.", 0, false);
1735  return -1;
1736  }
1737 
1738  }
1739 
1740  return 1;
1741 }
kXR_unt16 requestid
Definition: XProtocol.hh:511
kXR_char options[1]
Definition: XProtocol.hh:278
kXR_int16 arg1len
Definition: XProtocol.hh:460
#define kXR_isManager
Definition: XProtocol.hh:1198
kXR_unt16 requestid
Definition: XProtocol.hh:847
struct ClientCloseRequest close
Definition: XProtocol.hh:893
kXR_char fhandle[4]
Definition: XProtocol.hh:848
struct ClientMkdirRequest mkdir
Definition: XProtocol.hh:900
kXR_int32 dlen
Definition: XProtocol.hh:461
kXR_int64 offset
Definition: XProtocol.hh:682
kXR_unt16 requestid
Definition: XProtocol.hh:680
kXR_unt16 options
Definition: XProtocol.hh:513
struct ClientDirlistRequest dirlist
Definition: XProtocol.hh:894
kXR_unt16 requestid
Definition: XProtocol.hh:257
@ kXR_open_wrto
Definition: XProtocol.hh:499
@ kXR_delete
Definition: XProtocol.hh:483
@ kXR_open_read
Definition: XProtocol.hh:486
@ kXR_mkpath
Definition: XProtocol.hh:490
@ kXR_seqio
Definition: XProtocol.hh:498
@ kXR_new
Definition: XProtocol.hh:485
@ kXR_retstat
Definition: XProtocol.hh:493
struct ClientOpenRequest open
Definition: XProtocol.hh:902
@ kXR_dstat
Definition: XProtocol.hh:269
kXR_unt16 requestid
Definition: XProtocol.hh:458
kXR_char fhandle[4]
Definition: XProtocol.hh:681
kXR_char fhandle[4]
Definition: XProtocol.hh:258
@ kXR_read
Definition: XProtocol.hh:126
@ kXR_mkdir
Definition: XProtocol.hh:121
@ kXR_dirlist
Definition: XProtocol.hh:117
@ kXR_rm
Definition: XProtocol.hh:127
@ kXR_write
Definition: XProtocol.hh:132
@ kXR_rmdir
Definition: XProtocol.hh:128
@ kXR_mv
Definition: XProtocol.hh:122
@ kXR_stat
Definition: XProtocol.hh:130
@ kXR_close
Definition: XProtocol.hh:116
kXR_int32 dlen
Definition: XProtocol.hh:735
struct ClientRmRequest rm
Definition: XProtocol.hh:911
kXR_int32 dlen
Definition: XProtocol.hh:684
struct ClientReadRequest read
Definition: XProtocol.hh:909
struct ClientMvRequest mv
Definition: XProtocol.hh:901
kXR_unt16 requestid
Definition: XProtocol.hh:808
kXR_int32 dlen
Definition: XProtocol.hh:517
struct ClientRmdirRequest rmdir
Definition: XProtocol.hh:912
kXR_unt16 requestid
Definition: XProtocol.hh:445
kXR_unt16 mode
Definition: XProtocol.hh:512
kXR_char options[1]
Definition: XProtocol.hh:446
kXR_unt16 requestid
Definition: XProtocol.hh:733
@ kXR_mkdirpath
Definition: XProtocol.hh:440
struct ClientStatRequest stat
Definition: XProtocol.hh:915
kXR_int64 offset
Definition: XProtocol.hh:849
struct ClientWriteRequest write
Definition: XProtocol.hh:918
kXR_int32 dlen
Definition: XProtocol.hh:813
kXR_int32 rlen
Definition: XProtocol.hh:683
@ kXR_gw
Definition: XProtocol.hh:474
@ kXR_ur
Definition: XProtocol.hh:470
@ kXR_uw
Definition: XProtocol.hh:471
@ kXR_gr
Definition: XProtocol.hh:473
@ kXR_or
Definition: XProtocol.hh:476
@ kXR_isDir
Definition: XProtocol.hh:1263
kXR_unt16 requestid
Definition: XProtocol.hh:744
int kXR_int32
Definition: XPtypes.hh:89
unsigned char kXR_char
Definition: XPtypes.hh:65
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
std::vector< XrdOucIOVec2 > XrdHttpIOList
std::string obfuscateAuth(const std::string &input)
#define STR_NPOS
#define TRACE_DEBUG
Definition: XrdTrace.hh:36
#define TRACING(x)
Definition: XrdTrace.hh:70
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
virtual int ProcessReq(XrdHttpExtReq &)=0
static kXR_int32 myRole
Our role.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
int doStat(char *fname)
Perform a Stat request.
static char * listredir
Url to redirect to in the case a listing is requested.
static bool listdeny
If true, any form of listing is denied.
static bool embeddedstatic
If true, use the embedded css and icons.
const XrdHttpIOList & NextReadList()
return XrdHttpIOList for sending to read or readv
size_t getMaxRanges() const
return the maximum number of ranges that may be requested
bool isSingleRange()
indicates a single range (implied whole file, or single range) or empty file
int reqstate
State machine to talk to the bridge.
Definition: XrdHttpReq.hh:361
char fhandle[4]
Definition: XrdHttpReq.hh:354
int ReqReadV(const XrdHttpIOList &cl)
Prepare the buffers for sending a readv request.
Definition: XrdHttpReq.cc:451
int parseBody(char *body, long long len)
Parse the body of a request, assuming that it's XML and that it's entirely in memory.
Definition: XrdHttpReq.cc:96
std::vector< readahead_list > ralist
Definition: XrdHttpReq.hh:247
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:277
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:927
long fileflags
Definition: XrdHttpReq.hh:351
XrdOucString resourceplusopaque
The resource specified by the request, including all the opaque data.
Definition: XrdHttpReq.hh:281
std::string host
The host field specified in the req.
Definition: XrdHttpReq.hh:302
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum
The checksum that was ran for this request.
Definition: XrdHttpReq.hh:310
bool m_appended_hdr2cgistr
Definition: XrdHttpReq.hh:321
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
Definition: XrdHttpReq.cc:715
bool m_appended_asize
Track whether we already appended the oss.asize argument for PUTs.
Definition: XrdHttpReq.hh:323
XrdOucString m_resource_with_digest
Definition: XrdHttpReq.hh:315
long long filesize
Definition: XrdHttpReq.hh:350
bool readClosing
Definition: XrdHttpReq.hh:289
std::chrono::steady_clock::time_point startTime
Definition: XrdHttpReq.hh:370
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
const char * c_str() const
int erasefromend(int sz=0)
bool endswith(char c)
bool beginswith(char c)
int find(const char c, int start=0, bool forward=1)
int length() const
void append(const int i)
static std::map< std::string, T >::const_iterator caseInsensitiveFind(const std::map< std::string, T > &m, const std::string &lowerCaseSearchKey)
Definition: XrdOucTUtils.hh:79
virtual int setSF(kXR_char *fhandle, bool seton=false)=0
virtual bool Run(const char *xreqP, char *xdataP=0, int xdataL=0)=0

References allheaders, XrdOucString::append(), appendOpaque(), ClientMvRequest::arg1len, XrdOucString::beginswith(), XrdHttpProtocol::Bridge, XrdOucString::c_str(), XrdOucTUtils::caseInsensitiveFind(), ClientRequest::close, closeAfterError, XrdHttpProtocol::StaticPreloadInfo::data, DEBUG, depth, destination, ClientRequest::dirlist, ClientDirlistRequest::dlen, ClientMkdirRequest::dlen, ClientMvRequest::dlen, ClientOpenRequest::dlen, ClientReadRequest::dlen, ClientRmRequest::dlen, ClientRmdirRequest::dlen, ClientStatRequest::dlen, ClientWriteRequest::dlen, XrdHttpProtocol::doChksum(), XrdHttpProtocol::doStat(), XrdHttpProtocol::embeddedstatic, encode_opaque(), encode_str(), XrdOucString::endswith(), XrdOucString::erasefromend(), ClientCloseRequest::fhandle, ClientReadRequest::fhandle, ClientWriteRequest::fhandle, fhandle, fileflags, filesize, XrdOucString::find(), fopened, XrdHttpReadRangeHandler::getMaxRanges(), hdr2cgistr, host, XrdHttpReadRangeHandler::isSingleRange(), keepalive, kXR_close, kXR_delete, kXR_dirlist, kXR_dstat, kXR_gr, kXR_gw, kXR_isDir, kXR_isManager, kXR_mkdir, kXR_mkdirpath, kXR_mkpath, kXR_mv, kXR_new, kXR_open, kXR_open_read, kXR_open_wrto, kXR_or, kXR_read, kXR_retstat, kXR_rm, kXR_rmdir, kXR_seqio, kXR_stat, kXR_ur, kXR_uw, kXR_write, XrdHttpProtocol::StaticPreloadInfo::len, length, XrdOucString::length(), XrdHttpProtocol::listdeny, XrdHttpProtocol::listredir, m_appended_asize, m_appended_hdr2cgistr, m_req_cksum, m_resource_with_digest, m_want_digest, m_want_repr_digest, ClientRequest::mkdir, ClientOpenRequest::mode, ClientRequest::mv, XrdHttpProtocol::myRole, XrdHttpReadRangeHandler::NextReadList(), obfuscateAuth(), ClientReadRequest::offset, ClientWriteRequest::offset, opaque, ClientRequest::open, ClientDirlistRequest::options, ClientMkdirRequest::options, ClientOpenRequest::options, parseBody(), XrdHttpExtHandler::ProcessReq(), XrdOucEnv::Put(), ralist, ClientRequest::read, readClosing, readRangeHandler, ReqReadV(), reqstate, request, ClientCloseRequest::requestid, ClientDirlistRequest::requestid, ClientMkdirRequest::requestid, ClientMvRequest::requestid, ClientOpenRequest::requestid, ClientReadRequest::requestid, ClientRmRequest::requestid, ClientRmdirRequest::requestid, ClientStatRequest::requestid, ClientWriteRequest::requestid, reset(), resource, resourceplusopaque, ClientReadRequest::rlen, ClientRequest::rm, ClientRequest::rmdir, rtDELETE, rtGET, rtHEAD, rtMalformed, rtMKCOL, rtMOVE, rtOPTIONS, rtPATCH, rtPROPFIND, rtPUT, rtUnknown, rtUnset, XrdXrootd::Bridge::Run(), sendcontinue, XrdXrootd::Bridge::setSF(), startTime, ClientRequest::stat, XrdHttpProtocol::staticpreload, XrdHttpProtocol::staticredir, STR_NPOS, TRACE, TRACE_DEBUG, TRACEI, TRACING, ClientRequest::write, writtenbytes, and xrdreq.

Referenced by XrdHttpProtocol::Process().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Redir()

bool XrdHttpReq::Redir ( XrdXrootd::Bridge::Context &  info,
int  port,
const char *  hname 
)
virtual

Redirect the client to another host:port (or absolute URL).

The Redir() method is called when the client must be redirected to another host.

Parameters
infothe context associated with the result.
portdestination port in host byte order; when port < 0 and hname is an absolute URL (scheme://…), Location is that URL as-is (path included) and the original resource is not appended. Otherwise Location is built as http(s)://hname[:port]<resource>.
hnameDNS name / IP, or absolute URL when port < 0.
Returns
true continue normal processing. false terminate the bridge and close the link.
Parameters
infothe result context
portthe port number
hnamethe destination host

Implements XrdXrootd::Bridge::Result.

Definition at line 599 of file XrdHttpReq.cc.

602  {
603 
604 
605 
606  char hash[512];
607  hash[0] = '\0';
608 
609  bool invalid_host = false;
610 
611  if (!hname) {
612  invalid_host = true;
613  } else {
614  for (const char *c = hname; *c; ++c)
615  if (*c == '\r' || *c == '\n')
616  invalid_host = true;
617  }
618 
619  if (invalid_host) {
620  prot->SendSimpleResp(502, nullptr, nullptr, "Invalid redirect host", 0, false);
621  return keepalive;
622  }
623 
624  // port < 0 means XRootD URL-form redirect: hname is a full scheme://… URL
625  // (host+port+path).
626  // Do not prefix http(s):// and do not append the original resource
627  // otherwise, that would produce https://https://…/pfn/lfn.
628  const bool fullUrl = (port < 0);
629  if (fullUrl) {
630  TRACE(REQ, " XrdHttpReq::Redir using absolute URL: " << hname);
631  }
632 
633  // Beware, certain Ofs implementations (e.g. EOS) add opaque data directly to the host name
634  // This must be correctly treated here and appended to the opaque info
635  // that we may already have
636  char *pp = strchr((char *)hname, '?');
637  char *vardata = 0;
638  if (pp) {
639  *pp = '\0';
640  vardata = pp+1;
641  int varlen = strlen(vardata);
642 
643  //Now extract the remaining, vardata points to it
644  while(*vardata == '&' && varlen) {vardata++; varlen--;}
645  }
646 
647  // If the destination speaks cleartext HTTP, it needs the
648  // secret hash to reconstruct authorization info.
649  const bool destHttpCleartext =
650  fullUrl ? (strncmp(hname, "http://", 7) == 0) : (!prot->isdesthttps);
651 
652  std::string urlHashPath;
653  {
654  const std::string encodedResource =
655  fullUrl ? std::string() : encode_str(resource.c_str());
656  redirdest = httpBuildRedirectLocation(prot->isdesthttps, port, hname,
657  encodedResource.c_str()).c_str();
658 
659  // Derive the token path while hname is still truncated at '?', so the CGI
660  // stays out of the hash and both ends digest the same string.
661  if (fullUrl && destHttpCleartext)
663  }
664 
665  // Restore '?' so later uses of hname see the original string.
666  if (pp)
667  *pp = '?';
668 
669  // Here we put back the opaque info, if any
670  if (vardata) {
671  redirdest += "?&";
672  redirdest += encode_opaque(vardata).c_str();
673  }
674 
675  // Shall we put also the opaque data of the request? Maybe not
676  //int l;
677  //if (opaque && opaque->Env(l))
678  // redirdest += opaque->Env(l);
679 
680 
681  time_t timenow = 0;
682  if (destHttpCleartext && prot->ishttps) {
683  const char *hashPath = urlHashPath.empty() ? resource.c_str() : urlHashPath.c_str();
684  // If the destination is not https, then we suppose that it
685  // will need this token to fill its authorization info
686  timenow = time(0);
687  calcHashes(hash, hashPath, (kXR_int16) request,
688  &prot->SecEntity,
689  timenow,
690  prot->secretkey);
691  }
692 
693  if (hash[0]) {
694  appendOpaque(redirdest, &prot->SecEntity, hash, timenow);
695  } else
696  appendOpaque(redirdest, 0, 0, 0);
697 
698  if (!prot->strp_cgi_params.empty()) {
699  stripCgi(redirdest, prot->strp_cgi_params); /* appendOpaque() may have added credentials */
700  }
701 
702  TRACE(REQ, " XrdHttpReq::Redir Redirecting to " << redirdest.c_str());
703 
704  if (request != rtGET)
705  prot->SendSimpleResp(307, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
706  else
707  prot->SendSimpleResp(302, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
708 
709  bool ret_keepalive = keepalive; // reset() clears keepalive
710  reset();
711  return ret_keepalive;
712 };
short kXR_int16
Definition: XPtypes.hh:66
std::string httpCollapseSlashes(std::string path)
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
std::string httpPathFromAbsoluteUrl(const char *hname)
Path starting at the first / after the authority. An absent path is /.
std::string httpBuildRedirectLocation(bool destHttps, int port, const char *hname, const char *encodedResource)
std::string decode_str(const std::string &str)
void stripCgi(std::string &url, const std::unordered_set< std::string > &cgiKeys)
static char * secretkey
The key used to calculate the url hashes.
static bool isdesthttps
True if the redirections must be towards https targets.
static std::unordered_set< std::string > strp_cgi_params
CGI parameters (names) to strip from redirect URLs.
XrdSecEntity SecEntity
Authentication area.
XrdOucString redirdest
Definition: XrdHttpReq.hh:340

References appendOpaque(), XrdOucString::c_str(), calcHashes(), decode_str(), encode_opaque(), encode_str(), httpBuildRedirectLocation(), httpCollapseSlashes(), httpPathFromAbsoluteUrl(), XrdHttpProtocol::isdesthttps, keepalive, redirdest, request, reset(), resource, rtGET, XrdHttpProtocol::SecEntity, XrdHttpProtocol::secretkey, stripCgi(), XrdHttpProtocol::strp_cgi_params, and TRACE.

+ Here is the call graph for this function:

◆ ReqReadV()

int XrdHttpReq::ReqReadV ( const XrdHttpIOList &  cl)

Prepare the buffers for sending a readv request.

Definition at line 451 of file XrdHttpReq.cc.

451  {
452 
453 
454  // Now we build the protocol-ready read ahead list
455  // and also put the correct placeholders inside the cache
456  int n = cl.size();
457  ralist.clear();
458  ralist.reserve(n);
459 
460  int j = 0;
461  for (const auto &c: cl) {
462  ralist.emplace_back();
463  auto &ra = ralist.back();
464  memcpy(&ra.fhandle, this->fhandle, 4);
465 
466  ra.offset = c.offset;
467  ra.rlen = c.size;
468  j++;
469  }
470 
471  if (j > 0) {
472 
473  // Prepare a request header
474 
475  memset(&xrdreq, 0, sizeof (xrdreq));
476 
477  xrdreq.header.requestid = htons(kXR_readv);
478  xrdreq.readv.dlen = htonl(j * sizeof (struct readahead_list));
479 
480  clientMarshallReadAheadList(j);
481 
482 
483  }
484 
485  return (j * sizeof (struct readahead_list));
486 }
struct ClientReadVRequest readv
Definition: XProtocol.hh:910
@ kXR_readv
Definition: XProtocol.hh:138

References ClientReadVRequest::dlen, ClientRequest::header, kXR_readv, ralist, ClientRequest::readv, ClientRequestHdr::requestid, and xrdreq.

Referenced by ProcessHTTPReq().

+ Here is the caller graph for this function:

◆ reset()

void XrdHttpReq::reset ( )
virtual

State machine to talk to the bridge

Definition at line 2762 of file XrdHttpReq.cc.

2762  {
2763 
2764  TRACE(REQ, " XrdHttpReq request ended.");
2765 
2766  //if (xmlbody) xmlFreeDoc(xmlbody);
2768  readClosing = false;
2769  closeAfterError = false;
2770  writtenbytes = 0;
2771  etext.clear();
2772  redirdest = "";
2773 
2774  // // Here we should deallocate this
2775  // const struct iovec *iovP //!< pointer to data array
2776  // int iovN, //!< array count
2777  // int iovL, //!< byte count
2778  // bool final //!< true -> final result
2779 
2780 
2781  //xmlbody = 0;
2782  depth = 0;
2785  ralist.clear();
2786  ralist.shrink_to_fit();
2787 
2788  request = rtUnset;
2789  resource = "";
2790  allheaders.clear();
2791 
2792  // Reset the state of the request's digest request.
2793  m_want_digest.clear();
2794  m_digest_header.clear();
2795  m_req_cksum = nullptr;
2796 
2797  m_user_agent = "";
2798  m_origin = "";
2799 
2800  httpStatusCode = -1;
2801  initialStatusCode= -1;
2802  httpErrorCode = "";
2803  httpErrorBody = "";
2804 
2805  headerok = false;
2806  keepalive = true;
2807  length = 0;
2808  length_seen = false;
2809  filesize = 0;
2810  depth = 0;
2811  sendcontinue = false;
2812 
2813  m_transfer_encoding_chunked = false;
2814  m_current_chunk_size = -1;
2815  m_current_chunk_offset = 0;
2816 
2817  m_trailer_headers = false;
2818  m_status_trailer = false;
2819 
2821  reqstate = 0;
2822 
2823  memset(&xrdreq, 0, sizeof (xrdreq));
2824  memset(&xrdresp, 0, sizeof (xrdresp));
2826 
2827  etext.clear();
2828  redirdest = "";
2829 
2830  stringresp = "";
2831 
2832  host = "";
2833  destination = "";
2834  hdr2cgistr = "";
2835  m_appended_hdr2cgistr = false;
2836  m_appended_asize = false;
2837 
2838  iovP = 0;
2839  iovN = 0;
2840  iovL = 0;
2841 
2842  if (opaque) delete(opaque);
2843  opaque = 0;
2844 
2845  fopened = false;
2846  final = false;
2847  mScitag = -1;
2848 
2849  m_repr_digest.clear();
2850  m_want_repr_digest.clear();
2851 
2853  startTime = std::chrono::steady_clock::time_point::min();
2854 }
@ kXR_noErrorYet
Definition: XProtocol.hh:1069
@ kXR_noResponsesYet
Definition: XProtocol.hh:950
void reset()
resets this handler
std::string m_digest_header
The computed digest for the HTTP response header.
Definition: XrdHttpReq.hh:317
std::string stringresp
If we want to give a string as a response, we compose it here.
Definition: XrdHttpReq.hh:358
XrdHttpMonState monState
Definition: XrdHttpReq.hh:379

References allheaders, closeAfterError, depth, destination, etext, filesize, fopened, hdr2cgistr, headerok, host, iovL, iovN, iovP, keepalive, kXR_noErrorYet, kXR_noResponsesYet, length, length_seen, m_appended_asize, m_appended_hdr2cgistr, m_digest_header, m_origin, m_repr_digest, m_req_cksum, m_want_digest, m_want_repr_digest, monState, mScitag, NEW, opaque, ralist, readClosing, readRangeHandler, redirdest, reqstate, request, XrdHttpReadRangeHandler::reset(), resource, rtUnset, sendcontinue, startTime, stringresp, TRACE, writtenbytes, xrderrcode, xrdreq, and xrdresp.

Referenced by ~XrdHttpReq(), Data(), Done(), Error(), XrdHttpProtocol::Process(), ProcessHTTPReq(), and Redir().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ setHttpStatusCode()

void XrdHttpReq::setHttpStatusCode ( int  code)
inline

Definition at line 229 of file XrdHttpReq.hh.

229  {
230  httpStatusCode = code;
231  if (initialStatusCode < 0 && code >= 200 ) {
232  initialStatusCode = code;
233  }
234  }

◆ setTransferStatusHeader()

void XrdHttpReq::setTransferStatusHeader ( std::string &  header)

Definition at line 2081 of file XrdHttpReq.cc.

2081  {
2082  if (m_status_trailer) {
2083  if (header.empty()) {
2084  header += "Trailer: X-Transfer-Status";
2085  } else {
2086  header += "\r\nTrailer: X-Transfer-Status";
2087  }
2088  }
2089 }

◆ userAgent()

const std::string& XrdHttpReq::userAgent ( ) const
inline

Definition at line 265 of file XrdHttpReq.hh.

265 {return m_user_agent;}

Referenced by XrdHttpProtocol::Process().

+ Here is the caller graph for this function:

Member Data Documentation

◆ allheaders

std::map<std::string, std::string> XrdHttpReq::allheaders

Definition at line 274 of file XrdHttpReq.hh.

Referenced by parseLine(), ProcessHTTPReq(), and reset().

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 293 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ depth

int XrdHttpReq::depth

Definition at line 298 of file XrdHttpReq.hh.

Referenced by XrdHttpReq(), parseLine(), ProcessHTTPReq(), and reset().

◆ destination

std::string XrdHttpReq::destination

The destination field specified in the req.

Definition at line 304 of file XrdHttpReq.hh.

Referenced by parseLine(), ProcessHTTPReq(), and reset().

◆ etagval

long long XrdHttpReq::etagval

Definition at line 349 of file XrdHttpReq.hh.

◆ etext

std::string XrdHttpReq::etext

Definition at line 339 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 354 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 353 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 351 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat(), and ProcessHTTPReq().

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 352 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 350 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat(), ProcessHTTPReq(), and reset().

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 346 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

Definition at line 355 of file XrdHttpReq.hh.

Referenced by XrdHttpReq(), ProcessHTTPReq(), and reset().

◆ hdr2cgistr

std::string XrdHttpReq::hdr2cgistr

Additional opaque info that may come from the hdr2cgi directive.

Definition at line 320 of file XrdHttpReq.hh.

Referenced by addCgi(), appendOpaque(), ProcessHTTPReq(), and reset().

◆ headerok

bool XrdHttpReq::headerok

Tells if we have finished reading the header.

Definition at line 285 of file XrdHttpReq.hh.

Referenced by XrdHttpReq(), XrdHttpProtocol::Process(), and reset().

◆ host

std::string XrdHttpReq::host

The host field specified in the req.

Definition at line 302 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 345 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

Definition at line 344 of file XrdHttpReq.hh.

Referenced by Data(), Done(), and reset().

◆ iovP

const struct iovec* XrdHttpReq::iovP

The latest data chunks got from the xrd layer. These are valid only inside the callbacks!

pointer to data array

Definition at line 343 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

Definition at line 295 of file XrdHttpReq.hh.

Referenced by parseFirstLine(), parseLine(), ProcessHTTPReq(), Redir(), and reset().

◆ length

ssize_t XrdHttpReq::length

◆ length_seen

bool XrdHttpReq::length_seen {false}

Definition at line 297 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ m_appended_asize

bool XrdHttpReq::m_appended_asize {false}

Track whether we already appended the oss.asize argument for PUTs.

Definition at line 323 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

Definition at line 321 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_digest_header

std::string XrdHttpReq::m_digest_header

The computed digest for the HTTP response header.

Definition at line 317 of file XrdHttpReq.hh.

Referenced by reset().

◆ m_origin

std::string XrdHttpReq::m_origin

Definition at line 368 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ m_repr_digest

std::map<std::string,std::string> XrdHttpReq::m_repr_digest

Repr-Digest map where the key is the digest name and the value is the base64 encoded digest value.

Definition at line 373 of file XrdHttpReq.hh.

Referenced by XrdHttpExtReq::XrdHttpExtReq(), parseLine(), and reset().

◆ m_req_cksum

XrdHttpChecksumHandler::XrdHttpChecksumRawPtr XrdHttpReq::m_req_cksum = nullptr

The checksum that was ran for this request.

Definition at line 310 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_resource_with_digest

XrdOucString XrdHttpReq::m_resource_with_digest

The checksum algorithm is specified as part of the opaque data in the URL. Hence, when a digest is generated to satisfy a request, we cache the tweaked URL in this data member.

Definition at line 315 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ m_want_digest

std::string XrdHttpReq::m_want_digest

The requested digest type.

Definition at line 307 of file XrdHttpReq.hh.

Referenced by parseLine(), ProcessHTTPReq(), and reset().

◆ m_want_repr_digest

std::map<std::string,uint8_t> XrdHttpReq::m_want_repr_digest

Want-Repr-Digest map where the key is the digest name and the value is the preference (between 0 and 9)

Definition at line 377 of file XrdHttpReq.hh.

Referenced by XrdHttpExtReq::XrdHttpExtReq(), parseLine(), ProcessHTTPReq(), and reset().

◆ monState

XrdHttpMonState XrdHttpReq::monState

Definition at line 379 of file XrdHttpReq.hh.

Referenced by XrdHttpMon::Record(), and reset().

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 366 of file XrdHttpReq.hh.

Referenced by XrdHttpExtReq::XrdHttpExtReq(), XrdHttpReq(), and reset().

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

Definition at line 279 of file XrdHttpReq.hh.

Referenced by XrdHttpExtReq::XrdHttpExtReq(), XrdHttpReq(), appendOpaque(), parseLine(), XrdHttpProtocol::Process(), ProcessHTTPReq(), and reset().

◆ ralist

std::vector<readahead_list> XrdHttpReq::ralist

Definition at line 247 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), ReqReadV(), and reset().

◆ readClosing

bool XrdHttpReq::readClosing

Definition at line 289 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ readRangeHandler

XrdHttpReadRangeHandler XrdHttpReq::readRangeHandler

Tracking the next ranges of data to read during GET.

Definition at line 288 of file XrdHttpReq.hh.

Referenced by File(), parseLine(), ProcessHTTPReq(), and reset().

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 340 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 361 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::Process(), ProcessHTTPReq(), and reset().

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 269 of file XrdHttpReq.hh.

Referenced by Error(), parseFirstLine(), parseLine(), XrdHttpProtocol::Process(), ProcessHTTPReq(), XrdHttpMon::Record(), Redir(), and reset().

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 270 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

The resource specified by the request, stripped of opaque data.

Definition at line 277 of file XrdHttpReq.hh.

Referenced by XrdHttpExtReq::XrdHttpExtReq(), XrdHttpProtocol::Process(), ProcessHTTPReq(), Redir(), and reset().

◆ resourceplusopaque

XrdOucString XrdHttpReq::resourceplusopaque

The resource specified by the request, including all the opaque data.

Definition at line 281 of file XrdHttpReq.hh.

Referenced by XrdHttpExtReq::XrdHttpExtReq(), and ProcessHTTPReq().

◆ rwOpDone

unsigned int XrdHttpReq::rwOpDone

To coordinate multipart responses across multiple calls.

Definition at line 331 of file XrdHttpReq.hh.

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 331 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

Definition at line 299 of file XrdHttpReq.hh.

Referenced by parseLine(), ProcessHTTPReq(), and reset().

◆ startTime

std::chrono::steady_clock::time_point XrdHttpReq::startTime = std::chrono::steady_clock::time_point::min()

Definition at line 370 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::Process(), ProcessHTTPReq(), XrdHttpMon::Record(), and reset().

◆ stringresp

std::string XrdHttpReq::stringresp

If we want to give a string as a response, we compose it here.

Definition at line 358 of file XrdHttpReq.hh.

Referenced by reset().

◆ writtenbytes

long long XrdHttpReq::writtenbytes

In a long write, we track where we have arrived.

Definition at line 364 of file XrdHttpReq.hh.

Referenced by XrdHttpReq(), ProcessHTTPReq(), and reset().

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 338 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

Definition at line 334 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doChksum(), XrdHttpProtocol::doStat(), Error(), XrdHttpProtocol::Process(), ProcessHTTPReq(), ReqReadV(), and reset().

◆ xrdresp

XResponseType XrdHttpReq::xrdresp

The last response data we got.

Definition at line 337 of file XrdHttpReq.hh.

Referenced by Data(), Done(), Error(), and reset().


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