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::ResultWaitResp (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
 
long long length
 
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
 
XrdOucEnvopaque
 The opaque data, after parsing. More...
 
std::vector< readahead_listralist
 
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 65 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 76 of file XrdHttpReq.hh.

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

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 207 of file XrdHttpReq.hh.

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

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:2713

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 760 of file XrdHttpReq.cc.

760  {
761  if (hdr2cgistr.length() > 0) {
762  hdr2cgistr.append("&");
763  }
764  hdr2cgistr.append(key);
765  hdr2cgistr.append("=");
766  hdr2cgistr.append(value);
767 }
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.
Definition: XrdHttpReq.hh:318

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 652 of file XrdHttpReq.cc.

652  {
653 
654  int l = 0;
655  char * p = 0;
656  if (opaque)
657  p = opaque->Env(l);
658 
659  if (hdr2cgistr.empty() && (l < 2) && !hash) return;
660 
661  // this works in most cases, except if the url already contains the xrdhttp tokens
662  s = s + "?";
663  if (!hdr2cgistr.empty()) {
664  s += encode_opaque(hdr2cgistr).c_str();
665  }
666  if (p && (l > 1)) {
667  if (!hdr2cgistr.empty()) {
668  s = s + "&";
669  }
670  s = s + encode_opaque(p + 1).c_str();
671  }
672 
673  if (hash) {
674  if (l > 1) s += "&";
675  s += "xrdhttptk=";
676  s += hash;
677 
678  s += "&xrdhttptime=";
679  char buf[256];
680  sprintf(buf, "%lld", (long long) tnow);
681  s += buf;
682 
683  if (secent) {
684  if (secent->name) {
685  s += "&xrdhttpname=";
686  s += encode_str(secent->name).c_str();
687  }
688  }
689 
690  if (secent->vorg) {
691  s += "&xrdhttpvorg=";
692  s += encode_str(secent->vorg).c_str();
693  }
694 
695  if (secent->host) {
696  s += "&xrdhttphost=";
697  s += encode_str(secent->host).c_str();
698  }
699 
700  if (secent->moninfo) {
701  s += "&xrdhttpdn=";
702  s += encode_str(secent->moninfo).c_str();
703  }
704 
705  if (secent->role) {
706  s += "&xrdhttprole=";
707  s += encode_str(secent->role).c_str();
708  }
709 
710  if (secent->grps) {
711  s += "&xrdhttpgrps=";
712  s += encode_str(secent->grps).c_str();
713  }
714 
715  if (secent->endorsements) {
716  s += "&xrdhttpendorsements=";
717  s += encode_str(secent->endorsements).c_str();
718  }
719 
720  if (secent->credslen) {
721  s += "&xrdhttpcredslen=";
722  char buf[16];
723  sprintf(buf, "%d", secent->credslen);
724  s += encode_str(buf).c_str();
725  }
726 
727  if (secent->credslen) {
728  if (secent->creds) {
729  s += "&xrdhttpcreds=";
730  // Apparently this string might be not 0-terminated (!)
731  char *zerocreds = strndup(secent->creds, secent->credslen);
732  if (zerocreds) {
733  s += encode_str(zerocreds).c_str();
734  free(zerocreds);
735  }
736  }
737  }
738  }
739  }
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 444 of file XrdHttpReq.cc.

444  {
445  std::ostringstream s;
446 
447  s << "\r\n--" << token << "\r\n";
448  s << "Content-type: text/plain; charset=UTF-8\r\n";
449  s << "Content-range: bytes " << bytestart << "-" << byteend << "/" << fsz << "\r\n\r\n";
450 
451  return s.str();
452 }

◆ buildPartialHdrEnd()

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

Build the closing part for a multipart response.

Definition at line 454 of file XrdHttpReq.cc.

454  {
455  std::ostringstream s;
456 
457  s << "\r\n--" << token << "--\r\n";
458 
459  return s.str();
460 }

◆ 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 462 of file XrdHttpReq.cc.

468  {
469 
470  TRACE(REQ, " XrdHttpReq::Data! final=" << final);
471 
472  this->xrdresp = kXR_ok;
473  this->iovP = iovP_;
474  this->iovN = iovN_;
475  this->iovL = iovL_;
476  this->final = final_;
477 
478  if (PostProcessHTTPReq(final_)) reset();
479 
480  return true;
481 
482 };
@ 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:335
int iovL
byte count
Definition: XrdHttpReq.hh:343
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
Definition: XrdHttpReq.hh:341
int iovN
array count
Definition: XrdHttpReq.hh:342

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 508 of file XrdHttpReq.cc.

508  {
509 
510  TRACE(REQ, " XrdHttpReq::Done");
511 
512  xrdresp = kXR_ok;
513 
514  this->iovN = 0;
515 
516  int r = PostProcessHTTPReq(true);
517  // Beware, we don't have to reset() if the result is 0
518  if (r) reset();
519  if (r < 0) return false;
520 
521 
522  return true;
523 };

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 525 of file XrdHttpReq.cc.

528  {
529 
530  TRACE(REQ, " XrdHttpReq::Error");
531 
532  xrdresp = kXR_error;
533  xrderrcode = (XErrorCode) ecode;
534 
535  if (etext_) {
536  char *s = escapeXML(etext_);
537  this->etext = s;
538  free(s);
539  }
540 
541  auto rc = PostProcessHTTPReq();
542  if (rc) {
543  reset();
544  }
545 
546  // If we are servicing a GET on a directory, it'll generate an error for the default
547  // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
548  // generate a directory listing (if configured).
549  if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
550  return true;
551 
552  return rc == 0;
553 };
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:337
ReqType request
The request we got.
Definition: XrdHttpReq.hh:268
XErrorCode xrderrcode
Definition: XrdHttpReq.hh:336
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:332

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 484 of file XrdHttpReq.cc.

486  {
487 
488  // sendfile about to be sent by bridge for fetching data for GET:
489  // no https, no chunked+trailer, no multirange
490 
491  //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen);
492  int rc = info.Send(0, 0, 0, 0);
493  TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc);
494  bool start, finish;
495  // short read will be classed as error
496  if (rc) {
498  return false;
499  }
500 
501  if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
502  return false;
503 
504 
505  return true;
506 };
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 226 of file XrdHttpReq.hh.

226 { return httpStatusCode;}

◆ getInitialStatusCode()

int XrdHttpReq::getInitialStatusCode ( )
inline

Definition at line 225 of file XrdHttpReq.hh.

225 { 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 275 of file XrdHttpReq.cc.

275  {
276 
277  char *key = line;
278 
279  int pos;
280 
281  // Do the naive parsing
282  if (!line) return -1;
283 
284  // Look for the first space-delimited token
285  char *p = strchr((char *) line, (int) ' ');
286  if (!p) {
288  return -1;
289  }
290 
291 
292  pos = p - line;
293  // The first token cannot be too long
294  if (pos > MAX_TK_LEN - 1) {
296  return -2;
297  }
298 
299  // The first space-delimited char cannot be the first one
300  // this allows to deal with the case when a client sends a first line that starts with a space " GET / HTTP/1.1"
301  if(pos == 0) {
303  return -4;
304  }
305 
306  // the first token must be non empty
307  if (pos > 0) {
308  line[pos] = 0;
309  char *val = line + pos + 1;
310 
311  // Here we are supposed to initialize whatever flag or variable that is needed
312  // by looking at the first token of the line
313 
314  // The token is key
315  // The remainder is val, look for the resource
316  p = strchr((char *) val, (int) ' ');
317 
318  if (!p) {
320  line[pos] = ' ';
321  return -3;
322  }
323 
324  *p = '\0';
325  parseResource(val);
326 
327  *p = ' ';
328 
329  // Xlate the known header lines
330  if (!strcmp(key, "GET")) {
331  request = rtGET;
332  } else if (!strcmp(key, "HEAD")) {
333  request = rtHEAD;
334  } else if (!strcmp(key, "PUT")) {
335  request = rtPUT;
336  } else if (!strcmp(key, "POST")) {
337  request = rtPOST;
338  } else if (!strcmp(key, "PATCH")) {
339  request = rtPATCH;
340  } else if (!strcmp(key, "OPTIONS")) {
341  request = rtOPTIONS;
342  } else if (!strcmp(key, "DELETE")) {
343  request = rtDELETE;
344  } else if (!strcmp(key, "PROPFIND")) {
346  } else if (!strcmp(key, "MKCOL")) {
347  request = rtMKCOL;
348  } else if (!strcmp(key, "MOVE")) {
349  request = rtMOVE;
350  } else if (!strcmp(key, "COPY")) {
351  request = rtCOPY;
352  } else {
353  request = rtUnknown;
354  }
355 
356  requestverb = key;
357 
358  // The last token should be the protocol. If it is HTTP/1.0, then
359  // keepalive is disabled by default.
360  if (!strcmp(p+1, "HTTP/1.0\r\n")) {
361  keepalive = false;
362  }
363  line[pos] = ' ';
364  }
365 
366  return 0;
367 }
#define MAX_TK_LEN
Definition: XrdHttpReq.cc:67
std::string requestverb
Definition: XrdHttpReq.hh:269

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  length = atoll(val);
181 
182  } else if (!strcasecmp(key, "destination")) {
183  destination.assign(val, line+len-val);
184  trim(destination);
185  } else if (!strcasecmp(key, "want-digest")) {
186  // Discard Want-Repr-Digest in favor of Want-Digest
187  m_want_repr_digest.clear();
188  m_want_digest.assign(val, line + len - val);
190  //Transform the user requests' want-digest to lowercase
191  std::transform(m_want_digest.begin(), m_want_digest.end(), m_want_digest.begin(), ::tolower);
192  } else if (!strcasecmp(key, "depth")) {
193  depth = -1;
194  if (strcmp(val, "infinity"))
195  depth = atoll(val);
196 
197  } else if (!strcasecmp(key, "expect") && strstr(val, "100-continue")) {
198  sendcontinue = true;
199  } else if (!strcasecmp(key, "te") && strstr(val, "trailers")) {
200  m_trailer_headers = true;
201  } else if (!strcasecmp(key, "transfer-encoding") && strstr(val, "chunked")) {
202  m_transfer_encoding_chunked = true;
203  } else if (!strcasecmp(key, "x-transfer-status") && strstr(val, "true")) {
204  m_transfer_encoding_chunked = true;
205  m_status_trailer = true;
206  } else if (!strcasecmp(key, "scitag")) {
207  if(prot->pmarkHandle != nullptr) {
208  parseScitag(val);
209  }
210  } else if (!strcasecmp(key, "user-agent")) {
211  m_user_agent = val;
212  trim(m_user_agent);
213  } else if (!strcasecmp(key,"origin")) {
214  m_origin = val;
215  trim(m_origin);
216  } else if (!strcasecmp(key,"repr-digest")) {
218  } else if (!strcasecmp(key,"want-repr-digest")) {
219  if(m_want_digest.empty()) {
220  // If Want-Digest was set, don't parse want-repr-digest
222  }
223  } else {
224  // Some headers need to be translated into "local" cgi info.
225  auto it = std::find_if(prot->hdr2cgimap.begin(), prot->hdr2cgimap.end(),[key](const auto & item) {
226  return !strcasecmp(key,item.first.c_str());
227  });
228  if (it != prot->hdr2cgimap.end() && (opaque ? (0 == opaque->Get(it->second.c_str())) : true)) {
229  std::string s;
230  s.assign(val, line+len-val);
231  trim(s);
232  addCgi(it->second,s);
233  }
234  }
235 
236 
237  line[pos] = ':';
238  }
239 
240  return 0;
241 }
void trim(std::string &str)
Definition: XrdHttpReq.cc:78
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 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:302
std::map< std::string, uint8_t > m_want_repr_digest
Definition: XrdHttpReq.hh:375
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:371
std::string m_origin
Definition: XrdHttpReq.hh:366
std::string m_want_digest
The requested digest type.
Definition: XrdHttpReq.hh:305
std::map< std::string, std::string > allheaders
Definition: XrdHttpReq.hh:273
void addCgi(const std::string &key, const std::string &value)
Definition: XrdHttpReq.cc:760
bool sendcontinue
Definition: XrdHttpReq.hh:297
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69

References addCgi(), allheaders, depth, destination, XrdOucEnv::Get(), XrdHttpProtocol::hdr2cgimap, keepalive, length, m_origin, m_repr_digest, m_want_digest, m_want_repr_digest, MAX_TK_LEN, opaque, XrdHttpReadRangeHandler::ParseContentRange(), XrdHttpHeaderUtils::parseReprDigest(), 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 881 of file XrdHttpReq.cc.

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

References XrdOucString::append(), appendOpaque(), ClientMvRequest::arg1len, XrdOucString::beginswith(), XrdHttpProtocol::Bridge, XrdOucString::c_str(), 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(), 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.

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

Parameters
infothe context associated with the result.
portthe port number in host byte format.
hnamethe DNS name of the host or IP address is IPV4 or IPV6 format (i.e. "n.n.n.n" or "[ipv6_addr]").
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 555 of file XrdHttpReq.cc.

558  {
559 
560 
561 
562  char buf[512];
563  char hash[512];
564  hash[0] = '\0';
565 
566  if (prot->isdesthttps)
567  redirdest = "Location: https://";
568  else
569  redirdest = "Location: http://";
570 
571  // port < 0 signals switch to full URL
572  if (port < 0)
573  {
574  if (strncmp(hname, "file://", 7) == 0)
575  {
576  TRACE(REQ, " XrdHttpReq::Redir Switching to file:// ");
577  redirdest = "Location: "; // "file://" already contained in hname
578  }
579  }
580  // Beware, certain Ofs implementations (e.g. EOS) add opaque data directly to the host name
581  // This must be correctly treated here and appended to the opaque info
582  // that we may already have
583  char *pp = strchr((char *)hname, '?');
584  char *vardata = 0;
585  if (pp) {
586  *pp = '\0';
587  redirdest += hname;
588  vardata = pp+1;
589  int varlen = strlen(vardata);
590 
591  //Now extract the remaining, vardata points to it
592  while(*vardata == '&' && varlen) {vardata++; varlen--;}
593 
594  // Put the question mark back where it was
595  *pp = '?';
596  }
597  else
598  redirdest += hname;
599 
600  if (port > 0) {
601  sprintf(buf, ":%d", port);
602  redirdest += buf;
603  }
604 
605  redirdest += encode_str(resource.c_str()).c_str();
606 
607  // Here we put back the opaque info, if any
608  if (vardata) {
609  redirdest += "?&";
610  redirdest += encode_opaque(vardata).c_str();
611  }
612 
613  // Shall we put also the opaque data of the request? Maybe not
614  //int l;
615  //if (opaque && opaque->Env(l))
616  // redirdest += opaque->Env(l);
617 
618 
619  time_t timenow = 0;
620  if (!prot->isdesthttps && prot->ishttps) {
621  // If the destination is not https, then we suppose that it
622  // will need this token to fill its authorization info
623  timenow = time(0);
624  calcHashes(hash, this->resource.c_str(), (kXR_int16) request,
625  &prot->SecEntity,
626  timenow,
627  prot->secretkey);
628  }
629 
630  if (hash[0]) {
631  appendOpaque(redirdest, &prot->SecEntity, hash, timenow);
632  } else
633  appendOpaque(redirdest, 0, 0, 0);
634 
635  if (!prot->strp_cgi_params.empty()) {
636  stripCgi(redirdest, prot->strp_cgi_params); /* appendOpaque() may have added credentials */
637  }
638 
639  TRACE(REQ, " XrdHttpReq::Redir Redirecting to " << redirdest.c_str());
640 
641  if (request != rtGET)
642  prot->SendSimpleResp(307, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
643  else
644  prot->SendSimpleResp(302, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
645 
646  bool ret_keepalive = keepalive; // reset() clears keepalive
647  reset();
648  return ret_keepalive;
649 };
short kXR_int16
Definition: XPtypes.hh:66
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
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:338

References appendOpaque(), XrdOucString::c_str(), calcHashes(), encode_opaque(), encode_str(), 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 407 of file XrdHttpReq.cc.

407  {
408 
409 
410  // Now we build the protocol-ready read ahead list
411  // and also put the correct placeholders inside the cache
412  int n = cl.size();
413  ralist.clear();
414  ralist.reserve(n);
415 
416  int j = 0;
417  for (const auto &c: cl) {
418  ralist.emplace_back();
419  auto &ra = ralist.back();
420  memcpy(&ra.fhandle, this->fhandle, 4);
421 
422  ra.offset = c.offset;
423  ra.rlen = c.size;
424  j++;
425  }
426 
427  if (j > 0) {
428 
429  // Prepare a request header
430 
431  memset(&xrdreq, 0, sizeof (xrdreq));
432 
433  xrdreq.header.requestid = htons(kXR_readv);
434  xrdreq.readv.dlen = htonl(j * sizeof (struct readahead_list));
435 
436  clientMarshallReadAheadList(j);
437 
438 
439  }
440 
441  return (j * sizeof (struct readahead_list));
442 }
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 2713 of file XrdHttpReq.cc.

2713  {
2714 
2715  TRACE(REQ, " XrdHttpReq request ended.");
2716 
2717  //if (xmlbody) xmlFreeDoc(xmlbody);
2719  readClosing = false;
2720  closeAfterError = false;
2721  writtenbytes = 0;
2722  etext.clear();
2723  redirdest = "";
2724 
2725  // // Here we should deallocate this
2726  // const struct iovec *iovP //!< pointer to data array
2727  // int iovN, //!< array count
2728  // int iovL, //!< byte count
2729  // bool final //!< true -> final result
2730 
2731 
2732  //xmlbody = 0;
2733  depth = 0;
2736  ralist.clear();
2737  ralist.shrink_to_fit();
2738 
2739  request = rtUnset;
2740  resource = "";
2741  allheaders.clear();
2742 
2743  // Reset the state of the request's digest request.
2744  m_want_digest.clear();
2745  m_digest_header.clear();
2746  m_req_cksum = nullptr;
2747 
2748  m_user_agent = "";
2749  m_origin = "";
2750 
2751  httpStatusCode = -1;
2752  initialStatusCode= -1;
2753  httpErrorCode = "";
2754  httpErrorBody = "";
2755 
2756  headerok = false;
2757  keepalive = true;
2758  length = 0;
2759  filesize = 0;
2760  depth = 0;
2761  sendcontinue = false;
2762 
2763  m_transfer_encoding_chunked = false;
2764  m_current_chunk_size = -1;
2765  m_current_chunk_offset = 0;
2766 
2767  m_trailer_headers = false;
2768  m_status_trailer = false;
2769 
2771  reqstate = 0;
2772 
2773  memset(&xrdreq, 0, sizeof (xrdreq));
2774  memset(&xrdresp, 0, sizeof (xrdresp));
2776 
2777  etext.clear();
2778  redirdest = "";
2779 
2780  stringresp = "";
2781 
2782  host = "";
2783  destination = "";
2784  hdr2cgistr = "";
2785  m_appended_hdr2cgistr = false;
2786  m_appended_asize = false;
2787 
2788  iovP = 0;
2789  iovN = 0;
2790  iovL = 0;
2791 
2792  if (opaque) delete(opaque);
2793  opaque = 0;
2794 
2795  fopened = false;
2796  final = false;
2797  mScitag = -1;
2798 
2799  m_repr_digest.clear();
2800  m_want_repr_digest.clear();
2801 
2803  startTime = std::chrono::steady_clock::time_point::min();
2804 }
@ 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:315
std::string stringresp
If we want to give a string as a response, we compose it here.
Definition: XrdHttpReq.hh:356
XrdHttpMonState monState
Definition: XrdHttpReq.hh:377

References allheaders, closeAfterError, depth, destination, etext, filesize, fopened, hdr2cgistr, headerok, host, iovL, iovN, iovP, keepalive, kXR_noErrorYet, kXR_noResponsesYet, length, 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 228 of file XrdHttpReq.hh.

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

◆ setTransferStatusHeader()

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

Definition at line 2031 of file XrdHttpReq.cc.

2031  {
2032  if (m_status_trailer) {
2033  if (header.empty()) {
2034  header += "Trailer: X-Transfer-Status";
2035  } else {
2036  header += "\r\nTrailer: X-Transfer-Status";
2037  }
2038  }
2039 }

◆ userAgent()

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

Definition at line 264 of file XrdHttpReq.hh.

264 {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 273 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 292 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ depth

int XrdHttpReq::depth

Definition at line 296 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 302 of file XrdHttpReq.hh.

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

◆ etagval

long long XrdHttpReq::etagval

Definition at line 347 of file XrdHttpReq.hh.

◆ etext

std::string XrdHttpReq::etext

Definition at line 337 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 352 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 351 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 349 of file XrdHttpReq.hh.

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

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 350 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 348 of file XrdHttpReq.hh.

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

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 344 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

Definition at line 353 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 318 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 284 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 300 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 343 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

Definition at line 342 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 341 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

Definition at line 294 of file XrdHttpReq.hh.

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

◆ length

long long XrdHttpReq::length

◆ m_appended_asize

bool XrdHttpReq::m_appended_asize {false}

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

Definition at line 321 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

Definition at line 319 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 315 of file XrdHttpReq.hh.

Referenced by reset().

◆ m_origin

std::string XrdHttpReq::m_origin

Definition at line 366 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 371 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 308 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 313 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ m_want_digest

std::string XrdHttpReq::m_want_digest

The requested digest type.

Definition at line 305 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 375 of file XrdHttpReq.hh.

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

◆ monState

XrdHttpMonState XrdHttpReq::monState

Definition at line 377 of file XrdHttpReq.hh.

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

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 364 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

Definition at line 278 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 246 of file XrdHttpReq.hh.

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

◆ readClosing

bool XrdHttpReq::readClosing

Definition at line 288 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 287 of file XrdHttpReq.hh.

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 338 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 359 of file XrdHttpReq.hh.

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

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 268 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 269 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

Definition at line 276 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 280 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 329 of file XrdHttpReq.hh.

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 329 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

Definition at line 297 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 368 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 356 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 362 of file XrdHttpReq.hh.

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 336 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

Definition at line 332 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 335 of file XrdHttpReq.hh.

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


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