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
}
 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 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 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...
 
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
 
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum = nullptr
 The checksum that was ran for this request. More...
 
std::string m_req_digest
 The requested digest type. More...
 
XrdOucString m_resource_with_digest
 
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::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 71 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 

Definition at line 81 of file XrdHttpReq.hh.

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

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:284
long long length
Definition: XrdHttpReq.hh:285
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:274
bool closeAfterError
Definition: XrdHttpReq.hh:282
long long writtenbytes
In a long write, we track where we have arrived.
Definition: XrdHttpReq.hh:351
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:268
bool fopened
Definition: XrdHttpReq.hh:342
XrdHttpReadRangeHandler readRangeHandler
Tracking the next ranges of data to read during GET.
Definition: XrdHttpReq.hh:277

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

◆ ~XrdHttpReq()

XrdHttpReq::~XrdHttpReq ( )
virtual

Definition at line 111 of file XrdHttpReq.cc.

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

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

747  {
748  if (hdr2cgistr.length() > 0) {
749  hdr2cgistr.append("&");
750  }
751  hdr2cgistr.append(key);
752  hdr2cgistr.append("=");
753  hdr2cgistr.append(value);
754 }
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.
Definition: XrdHttpReq.hh:308

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

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

434  {
435  std::ostringstream s;
436 
437  s << "\r\n--" << token << "\r\n";
438  s << "Content-type: text/plain; charset=UTF-8\r\n";
439  s << "Content-range: bytes " << bytestart << "-" << byteend << "/" << fsz << "\r\n\r\n";
440 
441  return s.str();
442 }

◆ buildPartialHdrEnd()

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

Build the closing part 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 
449  return s.str();
450 }

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

458  {
459 
460  TRACE(REQ, " XrdHttpReq::Data! final=" << final);
461 
462  this->xrdresp = kXR_ok;
463  this->iovP = iovP_;
464  this->iovN = iovN_;
465  this->iovL = iovL_;
466  this->final = final_;
467 
468  if (PostProcessHTTPReq(final_)) reset();
469 
470  return true;
471 
472 };
@ kXR_ok
Definition: XProtocol.hh:899
#define TRACE(act, x)
Definition: XrdTrace.hh:63
XResponseType xrdresp
The last response data we got.
Definition: XrdHttpReq.hh:325
int iovL
byte count
Definition: XrdHttpReq.hh:333
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
Definition: XrdHttpReq.hh:331
int iovN
array count
Definition: XrdHttpReq.hh:332

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

498  {
499 
500  TRACE(REQ, " XrdHttpReq::Done");
501 
502  xrdresp = kXR_ok;
503 
504  this->iovN = 0;
505 
506  int r = PostProcessHTTPReq(true);
507  // Beware, we don't have to reset() if the result is 0
508  if (r) reset();
509  if (r < 0) return false;
510 
511 
512  return true;
513 };

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

518  {
519 
520  TRACE(REQ, " XrdHttpReq::Error");
521 
522  xrdresp = kXR_error;
523  xrderrcode = (XErrorCode) ecode;
524 
525  if (etext_) {
526  char *s = escapeXML(etext_);
527  this->etext = s;
528  free(s);
529  }
530 
531  auto rc = PostProcessHTTPReq();
532  if (rc) {
533  reset();
534  }
535 
536  // If we are servicing a GET on a directory, it'll generate an error for the default
537  // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
538  // generate a directory listing (if configured).
539  if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
540  return true;
541 
542  return rc == 0;
543 };
XErrorCode
Definition: XProtocol.hh:989
@ kXR_isDirectory
Definition: XProtocol.hh:1006
@ kXR_error
Definition: XProtocol.hh:903
struct ClientRequestHdr header
Definition: XProtocol.hh:846
kXR_unt16 requestid
Definition: XProtocol.hh:157
@ kXR_open
Definition: XProtocol.hh:122
char * escapeXML(const char *str)
std::string etext
Definition: XrdHttpReq.hh:327
ReqType request
The request we got.
Definition: XrdHttpReq.hh:258
XErrorCode xrderrcode
Definition: XrdHttpReq.hh:326
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:322

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

476  {
477 
478  // sendfile about to be sent by bridge for fetching data for GET:
479  // no https, no chunked+trailer, no multirange
480 
481  //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen);
482  int rc = info.Send(0, 0, 0, 0);
483  TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc);
484  bool start, finish;
485  // short read will be classed as error
486  if (rc) {
488  return false;
489  }
490 
491  if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
492  return false;
493 
494 
495  return true;
496 };
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:

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

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

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

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

References keepalive, MAX_TK_LEN, request, requestverb, 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 117 of file XrdHttpReq.cc.

117  {
118 
119  char *key = line;
120  int pos;
121 
122  // Do the parsing
123  if (!line) return -1;
124 
125 
126  char *p = strchr((char *) line, (int) ':');
127  if (!p) {
128 
130  return -1;
131  }
132 
133  pos = (p - line);
134  if (pos > (MAX_TK_LEN - 1)) {
135 
137  return -2;
138  }
139 
140  if (pos > 0) {
141  line[pos] = 0;
142  char *val = line + pos + 1;
143 
144  // Trim left
145  while ( (!isgraph(*val) || (!*val)) && (val < line+len)) val++;
146 
147  // We memorize the headers also as a string
148  // because external plugins may need to process it differently
149  std::string ss = val;
150  if(ss.length() >= 2 && ss.substr(ss.length() - 2, 2) != "\r\n") {
152  return -3;
153  }
154  trim(ss);
155  allheaders[key] = ss;
156 
157  // Here we are supposed to initialize whatever flag or variable that is needed
158  // by looking at the first token of the line
159  // The token is key
160  // The value is val
161 
162  // Screen out the needed header lines
163  if (!strcasecmp(key, "connection")) {
164 
165  if (!strcasecmp(val, "Keep-Alive\r\n")) {
166  keepalive = true;
167  } else if (!strcasecmp(val, "close\r\n")) {
168  keepalive = false;
169  }
170 
171  } else if (!strcasecmp(key, "host")) {
172  parseHost(val);
173  } else if (!strcasecmp(key, "range")) {
174  // (rfc2616 14.35.1) says if Range header contains any range
175  // which is syntactically invalid the Range header should be ignored.
176  // Therefore no need for the range handler to report an error.
178  } else if (!strcasecmp(key, "content-length")) {
179  length = atoll(val);
180 
181  } else if (!strcasecmp(key, "destination")) {
182  destination.assign(val, line+len-val);
183  trim(destination);
184  } else if (!strcasecmp(key, "want-digest")) {
185  m_req_digest.assign(val, line + len - val);
187  //Transform the user requests' want-digest to lowercase
188  std::transform(m_req_digest.begin(),m_req_digest.end(),m_req_digest.begin(),::tolower);
189  } else if (!strcasecmp(key, "depth")) {
190  depth = -1;
191  if (strcmp(val, "infinity"))
192  depth = atoll(val);
193 
194  } else if (!strcasecmp(key, "expect") && strstr(val, "100-continue")) {
195  sendcontinue = true;
196  } else if (!strcasecmp(key, "te") && strstr(val, "trailers")) {
197  m_trailer_headers = true;
198  } else if (!strcasecmp(key, "transfer-encoding") && strstr(val, "chunked")) {
199  m_transfer_encoding_chunked = true;
200  } else if (!strcasecmp(key, "x-transfer-status") && strstr(val, "true")) {
201  m_transfer_encoding_chunked = true;
202  m_status_trailer = true;
203  } else if (!strcasecmp(key, "scitag")) {
204  if(prot->pmarkHandle != nullptr) {
205  parseScitag(val);
206  }
207  } else if (!strcasecmp(key, "user-agent")) {
208  m_user_agent = val;
209  trim(m_user_agent);
210  } else if (!strcasecmp(key,"origin")) {
211  m_origin = val;
212  trim(m_origin);
213  } else {
214  // Some headers need to be translated into "local" cgi info.
215  auto it = std::find_if(prot->hdr2cgimap.begin(), prot->hdr2cgimap.end(),[key](const auto & item) {
216  return !strcasecmp(key,item.first.c_str());
217  });
218  if (it != prot->hdr2cgimap.end() && (opaque ? (0 == opaque->Get(it->second.c_str())) : true)) {
219  std::string s;
220  s.assign(val, line+len-val);
221  trim(s);
222  addCgi(it->second,s);
223  }
224  }
225 
226 
227  line[pos] = ':';
228  }
229 
230  return 0;
231 }
void trim(std::string &str)
Definition: XrdHttpReq.cc:77
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:292
std::string m_req_digest
The requested digest type.
Definition: XrdHttpReq.hh:295
std::string m_origin
Definition: XrdHttpReq.hh:355
std::map< std::string, std::string > allheaders
Definition: XrdHttpReq.hh:263
void addCgi(const std::string &key, const std::string &value)
Definition: XrdHttpReq.cc:747
bool sendcontinue
Definition: XrdHttpReq.hh:287
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69

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

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

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

References appendOpaque(), XrdOucString::c_str(), calcHashes(), encode_opaque(), encode_str(), XrdHttpProtocol::isdesthttps, keepalive, obfuscateAuth(), redirdest, request, reset(), resource, rtGET, XrdHttpProtocol::SecEntity, XrdHttpProtocol::secretkey, 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 397 of file XrdHttpReq.cc.

397  {
398 
399 
400  // Now we build the protocol-ready read ahead list
401  // and also put the correct placeholders inside the cache
402  int n = cl.size();
403  ralist.clear();
404  ralist.reserve(n);
405 
406  int j = 0;
407  for (const auto &c: cl) {
408  ralist.emplace_back();
409  auto &ra = ralist.back();
410  memcpy(&ra.fhandle, this->fhandle, 4);
411 
412  ra.offset = c.offset;
413  ra.rlen = c.size;
414  j++;
415  }
416 
417  if (j > 0) {
418 
419  // Prepare a request header
420 
421  memset(&xrdreq, 0, sizeof (xrdreq));
422 
423  xrdreq.header.requestid = htons(kXR_readv);
424  xrdreq.readv.dlen = htonl(j * sizeof (struct readahead_list));
425 
426  clientMarshallReadAheadList(j);
427 
428 
429  }
430 
431  return (j * sizeof (struct readahead_list));
432 }
struct ClientReadVRequest readv
Definition: XProtocol.hh:868
@ kXR_readv
Definition: XProtocol.hh:137

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

2700  {
2701 
2702  TRACE(REQ, " XrdHttpReq request ended.");
2703 
2704  //if (xmlbody) xmlFreeDoc(xmlbody);
2706  readClosing = false;
2707  closeAfterError = false;
2708  writtenbytes = 0;
2709  etext.clear();
2710  redirdest = "";
2711 
2712  // // Here we should deallocate this
2713  // const struct iovec *iovP //!< pointer to data array
2714  // int iovN, //!< array count
2715  // int iovL, //!< byte count
2716  // bool final //!< true -> final result
2717 
2718 
2719  //xmlbody = 0;
2720  depth = 0;
2723  ralist.clear();
2724  ralist.shrink_to_fit();
2725 
2726  request = rtUnset;
2727  resource = "";
2728  allheaders.clear();
2729 
2730  // Reset the state of the request's digest request.
2731  m_req_digest.clear();
2732  m_digest_header.clear();
2733  m_req_cksum = nullptr;
2734 
2736  m_user_agent = "";
2737  m_origin = "";
2738 
2739  headerok = false;
2740  keepalive = true;
2741  length = 0;
2742  filesize = 0;
2743  depth = 0;
2744  sendcontinue = false;
2745 
2746  m_transfer_encoding_chunked = false;
2747  m_current_chunk_size = -1;
2748  m_current_chunk_offset = 0;
2749 
2750  m_trailer_headers = false;
2751  m_status_trailer = false;
2752 
2754  reqstate = 0;
2755 
2756  memset(&xrdreq, 0, sizeof (xrdreq));
2757  memset(&xrdresp, 0, sizeof (xrdresp));
2759 
2760  etext.clear();
2761  redirdest = "";
2762 
2763  stringresp = "";
2764 
2765  host = "";
2766  destination = "";
2767  hdr2cgistr = "";
2768  m_appended_hdr2cgistr = false;
2769  m_appended_asize = false;
2770 
2771  iovP = 0;
2772  iovN = 0;
2773  iovL = 0;
2774 
2775 
2776  if (opaque) delete(opaque);
2777  opaque = 0;
2778 
2779  fopened = false;
2780 
2781  final = false;
2782 
2783  mScitag = -1;
2784 
2785  httpStatusCode = -1;
2786  httpErrorCode = "";
2787  httpErrorBody = "";
2788 
2789 }
@ kXR_noErrorYet
Definition: XProtocol.hh:1027
@ kXR_noResponsesYet
Definition: XProtocol.hh:908
void reset()
resets this handler
std::string m_digest_header
The computed digest for the HTTP response header.
Definition: XrdHttpReq.hh:305
std::string stringresp
If we want to give a string as a response, we compose it here.
Definition: XrdHttpReq.hh:345

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_req_cksum, m_req_digest, m_resource_with_digest, mScitag, opaque, ralist, readClosing, readRangeHandler, redirdest, reqstate, request, XrdHttpReadRangeHandler::reset(), resource, rtUnset, sendcontinue, 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:

◆ setTransferStatusHeader()

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

Definition at line 2002 of file XrdHttpReq.cc.

2002  {
2003  if (m_status_trailer) {
2004  if (header.empty()) {
2005  header += "Trailer: X-Transfer-Status";
2006  } else {
2007  header += "\r\nTrailer: X-Transfer-Status";
2008  }
2009  }
2010 }

◆ userAgent()

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

Definition at line 254 of file XrdHttpReq.hh.

254 {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 263 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 282 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ depth

int XrdHttpReq::depth

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

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

◆ etext

std::string XrdHttpReq::etext

Definition at line 327 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 341 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 340 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 338 of file XrdHttpReq.hh.

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

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 339 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 337 of file XrdHttpReq.hh.

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

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 334 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

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

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 333 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

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

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

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

Referenced by reset().

◆ m_origin

std::string XrdHttpReq::m_origin

Definition at line 355 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ m_req_cksum

XrdHttpChecksumHandler::XrdHttpChecksumRawPtr XrdHttpReq::m_req_cksum = nullptr

The checksum that was ran for this request.

Definition at line 298 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_req_digest

std::string XrdHttpReq::m_req_digest

The requested digest type.

Definition at line 295 of file XrdHttpReq.hh.

Referenced by parseLine(), 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 303 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 353 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

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

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 328 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 348 of file XrdHttpReq.hh.

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

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 258 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 259 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

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

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 319 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

Definition at line 287 of file XrdHttpReq.hh.

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

◆ stringresp

std::string XrdHttpReq::stringresp

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

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

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 326 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

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

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


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