XRootD
XrdHttpReq Class Reference

#include <XrdHttpReq.hh>

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

Public Types

enum  ReqType {
  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 ()
 
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
 
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_hdr2cgistr
 
std::string m_digest_header
 The computed digest for the HTTP response header. More...
 
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

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 215 of file XrdHttpReq.hh.

215  {
216  rtUnset = -1,
217  rtUnknown = 0,
218  rtMalformed,
219  rtGET,
220  rtHEAD,
221  rtPUT,
222  rtOPTIONS,
223  rtPATCH,
224  rtDELETE,
225  rtPROPFIND,
226  rtMKCOL,
227  rtMOVE,
228  rtPOST
229  };

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 162 of file XrdHttpReq.hh.

162  :
163  readRangeHandler(rcfg), keepalive(true) {
164 
165  prot = protinstance;
166  length = 0;
167  //xmlbody = 0;
168  depth = 0;
169  opaque = 0;
170  writtenbytes = 0;
171  fopened = false;
172  headerok = false;
173  mScitag = -1;
174  };
bool keepalive
Definition: XrdHttpReq.hh:254
long long length
Definition: XrdHttpReq.hh:255
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:248
long long writtenbytes
In a long write, we track where we have arrived.
Definition: XrdHttpReq.hh:319
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:242
bool fopened
Definition: XrdHttpReq.hh:310
XrdHttpReadRangeHandler readRangeHandler
Tracking the next ranges of data to read during GET.
Definition: XrdHttpReq.hh:251

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

◆ ~XrdHttpReq()

XrdHttpReq::~XrdHttpReq ( )
virtual

Definition at line 109 of file XrdHttpReq.cc.

109  {
110  //if (xmlbody) xmlFreeDoc(xmlbody);
111 
112  reset();
113 }
virtual void reset()
Definition: XrdHttpReq.cc:2710

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

784  {
785  if (hdr2cgistr.length() > 0) {
786  hdr2cgistr.append("&");
787  }
788  hdr2cgistr.append(key);
789  hdr2cgistr.append("=");
790  hdr2cgistr.append(value);
791 }
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.
Definition: XrdHttpReq.hh:278

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

627  {
628 
629  int l = 0;
630  char * p = 0;
631  if (opaque)
632  p = opaque->Env(l);
633 
634  if (hdr2cgistr.empty() && (l < 2) && !hash) return;
635 
636  // this works in most cases, except if the url already contains the xrdhttp tokens
637  s = s + "?";
638  if (!hdr2cgistr.empty()) {
639  char *s1 = quote(hdr2cgistr.c_str());
640  if (s1) {
641  s += s1;
642  free(s1);
643  }
644  }
645  if (p && (l > 1)) {
646  char *s1 = quote(p+1);
647  if (s1) {
648  if (!hdr2cgistr.empty()) {
649  s = s + "&";
650  }
651  s = s + s1;
652  free(s1);
653  }
654  }
655 
656 
657 
658  if (hash) {
659  if (l > 1) s += "&";
660  s += "xrdhttptk=";
661  s += hash;
662 
663  s += "&xrdhttptime=";
664  char buf[256];
665  sprintf(buf, "%lld", (long long) tnow);
666  s += buf;
667 
668  if (secent) {
669  if (secent->name) {
670  s += "&xrdhttpname=";
671  char *s1 = quote(secent->name);
672  if (s1) {
673  s += s1;
674  free(s1);
675  }
676  }
677 
678  if (secent->vorg) {
679  s += "&xrdhttpvorg=";
680  char *s1 = quote(secent->vorg);
681  if (s1) {
682  s += s1;
683  free(s1);
684  }
685  }
686 
687  if (secent->host) {
688  s += "&xrdhttphost=";
689  char *s1 = quote(secent->host);
690  if (s1) {
691  s += s1;
692  free(s1);
693  }
694  }
695 
696  if (secent->moninfo) {
697  s += "&xrdhttpdn=";
698  char *s1 = quote(secent->moninfo);
699  if (s1) {
700  s += s1;
701  free(s1);
702  }
703  }
704 
705  if (secent->role) {
706  s += "&xrdhttprole=";
707  char *s1 = quote(secent->role);
708  if (s1) {
709  s += s1;
710  free(s1);
711  }
712  }
713 
714  if (secent->grps) {
715  s += "&xrdhttpgrps=";
716  char *s1 = quote(secent->grps);
717  if (s1) {
718  s += s1;
719  free(s1);
720  }
721  }
722 
723  if (secent->endorsements) {
724  s += "&xrdhttpendorsements=";
725  char *s1 = quote(secent->endorsements);
726  if (s1) {
727  s += s1;
728  free(s1);
729  }
730  }
731 
732  if (secent->credslen) {
733  s += "&xrdhttpcredslen=";
734  char buf[16];
735  sprintf(buf, "%d", secent->credslen);
736  char *s1 = quote(buf);
737  if (s1) {
738  s += s1;
739  free(s1);
740  }
741  }
742 
743  if (secent->credslen) {
744  if (secent->creds) {
745  s += "&xrdhttpcreds=";
746  // Apparently this string might be not 0-terminated (!)
747  char *zerocreds = strndup(secent->creds, secent->credslen);
748  if (zerocreds) {
749  char *s1 = quote(zerocreds);
750  if (s1) {
751  s += s1;
752  free(s1);
753  }
754  free(zerocreds);
755  }
756  }
757  }
758 
759  }
760  }
761 
762 }
char * quote(const char *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, XrdSecEntity::endorsements, XrdOucEnv::Env(), XrdSecEntity::grps, hdr2cgistr, XrdSecEntity::host, XrdSecEntity::moninfo, XrdSecEntity::name, opaque, quote(), 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 424 of file XrdHttpReq.cc.

424  {
425  std::ostringstream s;
426 
427  s << "\r\n--" << token << "\r\n";
428  s << "Content-type: text/plain; charset=UTF-8\r\n";
429  s << "Content-range: bytes " << bytestart << "-" << byteend << "/" << fsz << "\r\n\r\n";
430 
431  return s.str();
432 }

◆ buildPartialHdrEnd()

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

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

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

448  {
449 
450  TRACE(REQ, " XrdHttpReq::Data! final=" << final);
451 
452  this->xrdresp = kXR_ok;
453  this->iovP = iovP_;
454  this->iovN = iovN_;
455  this->iovL = iovL_;
456  this->final = final_;
457 
458  if (PostProcessHTTPReq(final_)) reset();
459 
460  return true;
461 
462 };
@ kXR_ok
Definition: XProtocol.hh:897
#define TRACE(act, x)
Definition: XrdTrace.hh:63
XResponseType xrdresp
The last response data we got.
Definition: XrdHttpReq.hh:293
int iovL
byte count
Definition: XrdHttpReq.hh:301
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
Definition: XrdHttpReq.hh:299
int iovN
array count
Definition: XrdHttpReq.hh:300

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

488  {
489 
490  TRACE(REQ, " XrdHttpReq::Done");
491 
492  xrdresp = kXR_ok;
493 
494  this->iovN = 0;
495 
496  int r = PostProcessHTTPReq(true);
497  // Beware, we don't have to reset() if the result is 0
498  if (r) reset();
499  if (r < 0) return false;
500 
501 
502  return true;
503 };

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

508  {
509 
510  TRACE(REQ, " XrdHttpReq::Error");
511 
512  xrdresp = kXR_error;
513  xrderrcode = (XErrorCode) ecode;
514 
515  if (etext_) {
516  char *s = escapeXML(etext_);
517  this->etext = s;
518  free(s);
519  }
520 
521  if (PostProcessHTTPReq()) reset();
522 
523  // If we are servicing a GET on a directory, it'll generate an error for the default
524  // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
525  // generate a directory listing (if configured).
526  if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
527  return true;
528 
529  return false;
530 };
XErrorCode
Definition: XProtocol.hh:987
@ kXR_isDirectory
Definition: XProtocol.hh:1004
@ kXR_error
Definition: XProtocol.hh:901
struct ClientRequestHdr header
Definition: XProtocol.hh:844
kXR_unt16 requestid
Definition: XProtocol.hh:157
@ kXR_open
Definition: XProtocol.hh:122
char * escapeXML(const char *str)
std::string etext
Definition: XrdHttpReq.hh:295
ReqType request
The request we got.
Definition: XrdHttpReq.hh:232
XErrorCode xrderrcode
Definition: XrdHttpReq.hh:294
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:290

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

466  {
467 
468  // sendfile about to be sent by bridge for fetching data for GET:
469  // no https, no chunked+trailer, no multirange
470 
471  //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen);
472  int rc = info.Send(0, 0, 0, 0);
473  TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc);
474  bool start, finish;
475  // short read will be classed as error
476  if (rc) {
478  return false;
479  }
480 
481  if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
482  return false;
483 
484 
485  return true;
486 };
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 93 of file XrdHttpReq.cc.

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

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

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

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

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

References addCgi(), allheaders, depth, destination, XrdOucEnv::Get(), XrdHttpProtocol::hdr2cgimap, keepalive, length, 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 926 of file XrdHttpReq.cc.

926  {
927 
928  kXR_int32 l;
929 
931  if (!m_appended_hdr2cgistr && !hdr2cgistr.empty()) {
932  const char *p = strchr(resourceplusopaque.c_str(), '?');
933  if (p) {
935  } else {
937  }
938 
939  char *q = quote(hdr2cgistr.c_str());
941  if (TRACING(TRACE_DEBUG)) {
942  // The obfuscation of "authz" will only be done if the server http.header2cgi config contains something that maps a header to this "authz" cgi.
943  // Unfortunately the obfuscation code will be called no matter what is configured in http.header2cgi.
944  std::string header2cgistrObf = XrdOucUtils::obfuscate(hdr2cgistr, {"authz"}, '=', '&');
945 
946  TRACEI(DEBUG, "Appended header fields to opaque info: '"
947  << header2cgistrObf.c_str() << "'");
948 
949  }
950  // We assume that anything appended to the CGI str should also
951  // apply to the destination in case of a MOVE.
952  if (strchr(destination.c_str(), '?')) destination.append("&");
953  else destination.append("?");
954  destination.append(q);
955 
956  free(q);
957  m_appended_hdr2cgistr = true;
958  }
959 
960  // Verify if we have an external handler for this request
961  if (reqstate == 0) {
962  XrdHttpExtHandler *exthandler = prot->FindMatchingExtHandler(*this);
963  if (exthandler) {
964  XrdHttpExtReq xreq(this, prot);
965  int r = exthandler->ProcessReq(xreq);
966  reset();
967  if (!r) return 1; // All went fine, response sent
968  if (r < 0) return -1; // There was a hard error... close the connection
969 
970  return 1; // There was an error and a response was sent
971  }
972  }
973 
974  //
975  // Here we process the request locally
976  //
977 
978  switch (request) {
979  case XrdHttpReq::rtUnset:
981  {
982  prot->SendSimpleResp(400, NULL, NULL, (char *) "Request unknown", 0, false);
983  reset();
984  return -1;
985  }
987  {
988  prot->SendSimpleResp(400, NULL, NULL, (char *) "Request malformed", 0, false);
989  reset();
990  return -1;
991  }
992  case XrdHttpReq::rtHEAD:
993  {
994  if (reqstate == 0) {
995  // Always start with Stat; in the case of a checksum request, we'll have a follow-up query
996  if (prot->doStat((char *) resourceplusopaque.c_str())) {
997  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
998  return -1;
999  }
1000  return 0;
1001  } else {
1002  const char *opaque = strchr(resourceplusopaque.c_str(), '?');
1003  // Note that doChksum requires that the memory stays alive until the callback is invoked.
1005 
1007  if(!m_req_cksum) {
1008  // No HTTP IANA checksums have been configured by the server admin, return a "METHOD_NOT_ALLOWED" error
1009  prot->SendSimpleResp(403, NULL, NULL, (char *) "No HTTP-IANA compatible checksums have been configured.", 0, false);
1010  return -1;
1011  }
1012  if (!opaque) {
1013  m_resource_with_digest += "?cks.type=";
1015  } else {
1016  m_resource_with_digest += "&cks.type=";
1018  }
1019  if (prot->doChksum(m_resource_with_digest) < 0) {
1020  // In this case, the Want-Digest header was set and PostProcess gave the go-ahead to do a checksum.
1021  prot->SendSimpleResp(500, NULL, NULL, (char *) "Failed to create initial checksum request.", 0, false);
1022  return -1;
1023  }
1024  return 1;
1025  }
1026  }
1027  case XrdHttpReq::rtGET:
1028  {
1029 
1030  if (resource.beginswith("/static/")) {
1031 
1032  // This is a request for a /static resource
1033  // If we have to use the embedded ones then we return the ones in memory as constants
1034 
1035  // The sysadmin can always redirect the request to another host that
1036  // contains his static resources
1037 
1038  // We also allow xrootd to preread from the local disk all the files
1039  // that have to be served as static resources.
1040 
1041  if (prot->embeddedstatic) {
1042 
1043  // Default case: the icon and the css of the HTML rendering of XrdHttp
1044  if (resource == "/static/css/xrdhttp.css") {
1045  prot->SendSimpleResp(200, NULL, NULL, (char *) static_css_xrdhttp_css, static_css_xrdhttp_css_len, keepalive);
1046  reset();
1047  return keepalive ? 1 : -1;
1048  }
1049  if (resource == "/static/icons/xrdhttp.ico") {
1050  prot->SendSimpleResp(200, NULL, NULL, (char *) favicon_ico, favicon_ico_len, keepalive);
1051  reset();
1052  return keepalive ? 1 : -1;
1053  }
1054 
1055  }
1056 
1057  // If we are here then none of the embedded resources match (or they are disabled)
1058  // We may have to redirect to a host that is supposed to serve the static resources
1059  if (prot->staticredir) {
1060 
1061  XrdOucString s = "Location: ";
1062  s.append(prot->staticredir);
1063 
1064  if (s.endswith('/'))
1065  s.erasefromend(1);
1066 
1067  s.append(resource);
1068  appendOpaque(s, 0, 0, 0);
1069 
1070  prot->SendSimpleResp(302, NULL, (char *) s.c_str(), 0, 0, false);
1071  return -1;
1072 
1073 
1074  } else {
1075 
1076  // We lookup the requested path in a hash containing the preread files
1077  if (prot->staticpreload) {
1079  if (mydata) {
1080  prot->SendSimpleResp(200, NULL, NULL, (char *) mydata->data, mydata->len, keepalive);
1081  reset();
1082  return keepalive ? 1 : -1;
1083  }
1084  }
1085 
1086  }
1087 
1088 
1089  }
1090 
1091  // The reqstate parameter basically moves us through a simple state machine.
1092  // To optimize things, we start off by opening the file; if it turns out to be a directory, then
1093  // we close the file handle and switch to doing a HTML-based rendering of the directory. This
1094  // avoids needing to always to do "stat" first to determine the next step (since the file-open also
1095  // does a "stat").
1096  // - 0: Perform an open on the resource
1097  // - 1: Perform a checksum request on the resource (only if requested in header; otherwise skipped)
1098  // - 2: Perform a close (for dirlist only)
1099  // - 3: Perform a dirlist.
1100  // - 4+: Reads from file; if at end, perform a close.
1101  switch (reqstate) {
1102  case 0: // Open the path for reading.
1103  {
1104  memset(&xrdreq, 0, sizeof (ClientRequest));
1105  xrdreq.open.requestid = htons(kXR_open);
1106  l = resourceplusopaque.length() + 1;
1107  xrdreq.open.dlen = htonl(l);
1108  xrdreq.open.mode = 0;
1110 
1111  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1112  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
1113  return -1;
1114  }
1115 
1116  // Prepare to chunk up the request
1117  writtenbytes = 0;
1118 
1119  // We want to be invoked again after this request is finished
1120  return 0;
1121  }
1122  case 1: // Checksum request
1123  if (!(fileflags & kXR_isDir) && !m_req_digest.empty()) {
1124  // In this case, the Want-Digest header was set.
1125  bool has_opaque = strchr(resourceplusopaque.c_str(), '?');
1126  // Note that doChksum requires that the memory stays alive until the callback is invoked.
1128  if(!m_req_cksum) {
1129  // No HTTP IANA checksums have been configured by the server admin, return a "METHOD_NOT_ALLOWED" error
1130  prot->SendSimpleResp(403, NULL, NULL, (char *) "No HTTP-IANA compatible checksums have been configured.", 0, false);
1131  return -1;
1132  }
1134  if (has_opaque) {
1135  m_resource_with_digest += "&cks.type=";
1137  } else {
1138  m_resource_with_digest += "?cks.type=";
1140  }
1141  if (prot->doChksum(m_resource_with_digest) < 0) {
1142  prot->SendSimpleResp(500, NULL, NULL, (char *) "Failed to start internal checksum request to satisfy Want-Digest header.", 0, false);
1143  return -1;
1144  }
1145  return 0;
1146  } else {
1147  TRACEI(DEBUG, "No checksum requested; skipping to request state 2");
1148  reqstate += 1;
1149  }
1150  // fallthrough
1151  case 2: // Close file handle for directory
1152  if ((fileflags & kXR_isDir) && fopened) {
1153  memset(&xrdreq, 0, sizeof (ClientRequest));
1154  xrdreq.close.requestid = htons(kXR_close);
1155  memcpy(xrdreq.close.fhandle, fhandle, 4);
1156 
1157  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1158  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run close request.", 0, false);
1159  return -1;
1160  }
1161  return 0;
1162  } else {
1163  reqstate += 1;
1164  }
1165  // fallthrough
1166  case 3: // List directory
1167  if (fileflags & kXR_isDir) {
1168  if (prot->listdeny) {
1169  prot->SendSimpleResp(503, NULL, NULL, (char *) "Listings are disabled.", 0, false);
1170  return -1;
1171  }
1172 
1173  if (prot->listredir) {
1174  XrdOucString s = "Location: ";
1175  s.append(prot->listredir);
1176 
1177  if (s.endswith('/'))
1178  s.erasefromend(1);
1179 
1180  s.append(resource);
1181  appendOpaque(s, 0, 0, 0);
1182 
1183  prot->SendSimpleResp(302, NULL, (char *) s.c_str(), 0, 0, false);
1184  return -1;
1185  }
1186 
1187  std::string res;
1188  res = resourceplusopaque.c_str();
1189 
1190  // --------- DIRLIST
1191  memset(&xrdreq, 0, sizeof (ClientRequest));
1194  l = res.length() + 1;
1195  xrdreq.dirlist.dlen = htonl(l);
1196 
1197  if (!prot->Bridge->Run((char *) &xrdreq, (char *) res.c_str(), l)) {
1198  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
1199  return -1;
1200  }
1201 
1202  // We don't want to be invoked again after this request is finished
1203  return 1;
1204  }
1205  else {
1206  reqstate += 1;
1207  }
1208  // fallthrough
1209  case 4:
1210  {
1211  auto retval = ReturnGetHeaders();
1212  if (retval) {
1213  return retval;
1214  }
1215  }
1216  // fallthrough
1217  default: // Read() or Close(); reqstate is 4+
1218  {
1219  const XrdHttpIOList &readChunkList = readRangeHandler.NextReadList();
1220 
1221  // Close() if we have finished, otherwise read the next chunk
1222 
1223  // --------- CLOSE
1224  if ( readChunkList.empty() )
1225  {
1226 
1227  memset(&xrdreq, 0, sizeof (ClientRequest));
1228  xrdreq.close.requestid = htons(kXR_close);
1229  memcpy(xrdreq.close.fhandle, fhandle, 4);
1230 
1231  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1232  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run close request.", 0, false);
1233  return -1;
1234  }
1235 
1236  // We have finished
1237  readClosing = true;
1238  return 1;
1239 
1240  }
1241  // --------- READ or READV
1242 
1243  if ( readChunkList.size() == 1 ) {
1244  // Use a read request for single range
1245 
1246  long l;
1247  long long offs;
1248 
1249  // --------- READ
1250  memset(&xrdreq, 0, sizeof (xrdreq));
1251  xrdreq.read.requestid = htons(kXR_read);
1252  memcpy(xrdreq.read.fhandle, fhandle, 4);
1253  xrdreq.read.dlen = 0;
1254 
1255  offs = readChunkList[0].offset;
1256  l = readChunkList[0].size;
1257 
1258  xrdreq.read.offset = htonll(offs);
1259  xrdreq.read.rlen = htonl(l);
1260 
1261  // If we are using HTTPS or if the client requested trailers, or if the
1262  // read concerns a multirange reponse, disable sendfile
1263  // (in the latter two cases, the extra framing is only done in PostProcessHTTPReq)
1264  if (prot->ishttps || (m_transfer_encoding_chunked && m_trailer_headers) ||
1266  if (!prot->Bridge->setSF((kXR_char *) fhandle, false)) {
1267  TRACE(REQ, " XrdBridge::SetSF(false) failed.");
1268 
1269  }
1270  }
1271 
1272 
1273 
1274  if (l <= 0) {
1275  if (l < 0) {
1276  TRACE(ALL, " Data sizes mismatch.");
1277  return -1;
1278  }
1279  else {
1280  TRACE(ALL, " No more bytes to send.");
1281  reset();
1282  return 1;
1283  }
1284  }
1285 
1286  if ((offs >= filesize) || (offs+l > filesize)) {
1287  TRACE(ALL, " Requested range " << l << "@" << offs <<
1288  " is past the end of file (" << filesize << ")");
1289  //prot->SendSimpleResp(522, NULL, NULL, (char *) "Invalid range request", 0);
1290  return -1;
1291  }
1292 
1293  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1294  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run read request.", 0, false);
1295  return -1;
1296  }
1297  } else {
1298  // --------- READV
1299 
1300  length = ReqReadV(readChunkList);
1301 
1302  if (!prot->Bridge->Run((char *) &xrdreq, (char *) &ralist[0], length)) {
1303  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run read request.", 0, false);
1304  return -1;
1305  }
1306 
1307  }
1308 
1309  // We want to be invoked again after this request is finished
1310  return 0;
1311  } // case 3+
1312 
1313  } // switch (reqstate)
1314 
1315 
1316  } // case XrdHttpReq::rtGET
1317 
1318  case XrdHttpReq::rtPUT:
1319  {
1320  //if (prot->ishttps) {
1321  //prot->SendSimpleResp(501, NULL, NULL, (char *) "HTTPS not supported yet for direct writing. Sorry.", 0);
1322  //return -1;
1323  //}
1324 
1325  if (!fopened) {
1326 
1327  // --------- OPEN for write!
1328  memset(&xrdreq, 0, sizeof (ClientRequest));
1329  xrdreq.open.requestid = htons(kXR_open);
1330  l = resourceplusopaque.length() + 1;
1331  xrdreq.open.dlen = htonl(l);
1332  xrdreq.open.mode = htons(kXR_ur | kXR_uw | kXR_gw | kXR_gr | kXR_or);
1333  if (! XrdHttpProtocol::usingEC)
1335  else
1337 
1338  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1339  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, keepalive);
1340  return -1;
1341  }
1342 
1343 
1344  // We want to be invoked again after this request is finished
1345  // Only if there is data to fetch from the socket or there will
1346  // never be more data
1347  if (prot->BuffUsed() > 0 || (length == 0 && !sendcontinue))
1348  return 0;
1349 
1350  return 1;
1351 
1352  } else {
1353 
1354  if (m_transfer_encoding_chunked) {
1355  if (m_current_chunk_size == m_current_chunk_offset) {
1356  // Chunk has been consumed; we now must process the CRLF.
1357  // Note that we don't support trailer headers.
1358  if (prot->BuffUsed() < 2) return 1;
1359  if (prot->myBuffStart[0] != '\r' || prot->myBuffStart[1] != '\n') {
1360  prot->SendSimpleResp(400, NULL, NULL, (char *) "Invalid trailing chunk encoding.", 0, keepalive);
1361  return -1;
1362  }
1363  prot->BuffConsume(2);
1364  if (m_current_chunk_size == 0) {
1365  // All data has been sent. Turn off chunk processing and
1366  // set the bytes written and length appropriately; on next callback,
1367  // we will hit the close() block below.
1368  m_transfer_encoding_chunked = false;
1369  length = writtenbytes;
1370  return ProcessHTTPReq();
1371  }
1372  m_current_chunk_size = -1;
1373  m_current_chunk_offset = 0;
1374  // If there is more data, we try to process the next chunk; otherwise, return
1375  if (!prot->BuffUsed()) return 1;
1376  }
1377  if (-1 == m_current_chunk_size) {
1378 
1379  // Parse out the next chunk size.
1380  long long idx = 0;
1381  bool found_newline = false;
1382  // Set a maximum size of chunk we will allow
1383  // Nginx sets this to "NGX_MAX_OFF_T_VALUE", which is 9223372036854775807 (a some crazy number)
1384  // We set it to 1TB, which is 1099511627776
1385  // This is to prevent a malicious client from sending a very large chunk size
1386  // or a malformed chunk request.
1387  // 1TB in base-16 is 0x40000000000, so only allow 11 characters, plus the CRLF
1388  long long max_chunk_size_chars = std::min(static_cast<long long>(prot->BuffUsed()), static_cast<long long>(13));
1389  for (; idx < max_chunk_size_chars; idx++) {
1390  if (prot->myBuffStart[idx] == '\n') {
1391  found_newline = true;
1392  break;
1393  }
1394  }
1395  // If we found a new line, but it is the first character in the buffer (no chunk length)
1396  // or if the previous character is not a CR.
1397  if (found_newline && ((idx == 0) || prot->myBuffStart[idx-1] != '\r')) {
1398  prot->SendSimpleResp(400, NULL, NULL, (char *)"Invalid chunked encoding", 0, false);
1399  TRACE(REQ, "XrdHTTP PUT: Sending invalid chunk encoding. Start of chunk should have had a length, followed by a CRLF.");
1400  return -1;
1401  }
1402  if (found_newline) {
1403  char *endptr = NULL;
1404  std::string line_contents(prot->myBuffStart, idx);
1405  long long chunk_contents = strtol(line_contents.c_str(), &endptr, 16);
1406  // Chunk sizes can be followed by trailer information or CRLF
1407  if (*endptr != ';' && *endptr != '\r') {
1408  prot->SendSimpleResp(400, NULL, NULL, (char *)"Invalid chunked encoding", 0, false);
1409  TRACE(REQ, "XrdHTTP PUT: Sending invalid chunk encoding. Chunk size was not followed by a ';' or CR." << __LINE__);
1410  return -1;
1411  }
1412  m_current_chunk_size = chunk_contents;
1413  m_current_chunk_offset = 0;
1414  prot->BuffConsume(idx + 1);
1415  TRACE(REQ, "XrdHTTP PUT: next chunk from client will be " << m_current_chunk_size << " bytes");
1416  } else {
1417  // Need more data!
1418  return 1;
1419  }
1420  }
1421 
1422  if (m_current_chunk_size == 0) {
1423  // All data has been sent. Invoke this routine again immediately to process CRLF
1424  return ProcessHTTPReq();
1425  } else {
1426  // At this point, we have a chunk size defined and should consume payload data
1427  memset(&xrdreq, 0, sizeof (xrdreq));
1428  xrdreq.write.requestid = htons(kXR_write);
1429  memcpy(xrdreq.write.fhandle, fhandle, 4);
1430 
1431  long long chunk_bytes_remaining = m_current_chunk_size - m_current_chunk_offset;
1432  long long bytes_to_write = std::min(static_cast<long long>(prot->BuffUsed()),
1433  chunk_bytes_remaining);
1434 
1435  xrdreq.write.offset = htonll(writtenbytes);
1436  xrdreq.write.dlen = htonl(bytes_to_write);
1437 
1438  TRACEI(REQ, "XrdHTTP PUT: Writing chunk of size " << bytes_to_write << " starting with '" << *(prot->myBuffStart) << "'" << " with " << chunk_bytes_remaining << " bytes remaining in the chunk");
1439  if (!prot->Bridge->Run((char *) &xrdreq, prot->myBuffStart, bytes_to_write)) {
1440  prot->SendSimpleResp(500, NULL, NULL, (char *) "Could not run write request.", 0, false);
1441  return -1;
1442  }
1443  // If there are more bytes in the buffer, then immediately call us after the
1444  // write is finished; otherwise, wait for data.
1445  return (prot->BuffUsed() > chunk_bytes_remaining) ? 0 : 1;
1446  }
1447  } else if (writtenbytes < length) {
1448 
1449 
1450  // --------- WRITE
1451  memset(&xrdreq, 0, sizeof (xrdreq));
1452  xrdreq.write.requestid = htons(kXR_write);
1453  memcpy(xrdreq.write.fhandle, fhandle, 4);
1454 
1455  long long bytes_to_read = std::min(static_cast<long long>(prot->BuffUsed()),
1456  length - writtenbytes);
1457 
1458  xrdreq.write.offset = htonll(writtenbytes);
1459  xrdreq.write.dlen = htonl(bytes_to_read);
1460 
1461  TRACEI(REQ, "Writing " << bytes_to_read);
1462  if (!prot->Bridge->Run((char *) &xrdreq, prot->myBuffStart, bytes_to_read)) {
1463  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run write request.", 0, false);
1464  return -1;
1465  }
1466 
1467  if (writtenbytes + prot->BuffUsed() >= length)
1468  // Trigger an immediate recall after this request has finished
1469  return 0;
1470  else
1471  // We want to be invoked again after this request is finished
1472  // only if there is pending data
1473  return 1;
1474 
1475 
1476 
1477  } else {
1478 
1479  // --------- CLOSE
1480  memset(&xrdreq, 0, sizeof (ClientRequest));
1481  xrdreq.close.requestid = htons(kXR_close);
1482  memcpy(xrdreq.close.fhandle, fhandle, 4);
1483 
1484 
1485  if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1486  prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run close request.", 0, false);
1487  return -1;
1488  }
1489 
1490  // We have finished
1491  return 1;
1492 
1493  }
1494 
1495  }
1496 
1497  break;
1498 
1499  }
1500  case XrdHttpReq::rtOPTIONS:
1501  {
1502  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);
1503  reset();
1504  return keepalive ? 1 : -1;
1505  }
1506  case XrdHttpReq::rtDELETE:
1507  {
1508 
1509 
1510  switch (reqstate) {
1511 
1512  case 0: // Stat()
1513  {
1514 
1515 
1516  // --------- STAT is always the first step
1517  memset(&xrdreq, 0, sizeof (ClientRequest));
1518  xrdreq.stat.requestid = htons(kXR_stat);
1519  std::string s = resourceplusopaque.c_str();
1520 
1521 
1522  l = resourceplusopaque.length() + 1;
1523  xrdreq.stat.dlen = htonl(l);
1524 
1525  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1526  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1527  return -1;
1528  }
1529 
1530  // We need to be invoked again to complete the request
1531  return 0;
1532  }
1533  default:
1534 
1535  if (fileflags & kXR_isDir) {
1536  // --------- RMDIR
1537  memset(&xrdreq, 0, sizeof (ClientRequest));
1538  xrdreq.rmdir.requestid = htons(kXR_rmdir);
1539 
1540  std::string s = resourceplusopaque.c_str();
1541 
1542  l = s.length() + 1;
1543  xrdreq.rmdir.dlen = htonl(l);
1544 
1545  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1546  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run rmdir request.", 0, false);
1547  return -1;
1548  }
1549  } else {
1550  // --------- DELETE
1551  memset(&xrdreq, 0, sizeof (ClientRequest));
1552  xrdreq.rm.requestid = htons(kXR_rm);
1553 
1554  std::string s = resourceplusopaque.c_str();
1555 
1556  l = s.length() + 1;
1557  xrdreq.rm.dlen = htonl(l);
1558 
1559  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1560  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run rm request.", 0, false);
1561  return -1;
1562  }
1563  }
1564 
1565 
1566  // We don't want to be invoked again after this request is finished
1567  return 1;
1568 
1569  }
1570 
1571 
1572 
1573  }
1574  case XrdHttpReq::rtPATCH:
1575  {
1576  prot->SendSimpleResp(501, NULL, NULL, (char *) "Request not supported yet.", 0, false);
1577 
1578  return -1;
1579  }
1581  {
1582 
1583 
1584 
1585  switch (reqstate) {
1586 
1587  case 0: // Stat() and add the current item to the list of the things to send
1588  {
1589 
1590  if (length > 0) {
1591  TRACE(REQ, "Reading request body " << length << " bytes.");
1592  char *p = 0;
1593  // We have to specifically read all the request body
1594 
1595  if (prot->BuffgetData(length, &p, true) < length) {
1596  prot->SendSimpleResp(501, NULL, NULL, (char *) "Error in getting the PROPFIND request body.", 0, false);
1597  return -1;
1598  }
1599 
1600  if ((depth > 1) || (depth < 0)) {
1601  prot->SendSimpleResp(501, NULL, NULL, (char *) "Invalid depth value.", 0, false);
1602  return -1;
1603  }
1604 
1605 
1606  parseBody(p, length);
1607  }
1608 
1609 
1610  // --------- STAT is always the first step
1611  memset(&xrdreq, 0, sizeof (ClientRequest));
1612  xrdreq.stat.requestid = htons(kXR_stat);
1613  std::string s = resourceplusopaque.c_str();
1614 
1615 
1616  l = resourceplusopaque.length() + 1;
1617  xrdreq.stat.dlen = htonl(l);
1618 
1619  if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1620  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1621  return -1;
1622  }
1623 
1624 
1625  if (depth == 0) {
1626  // We don't need to be invoked again
1627  return 1;
1628  } else
1629  // We need to be invoked again to complete the request
1630  return 0;
1631 
1632 
1633 
1634  break;
1635  }
1636 
1637  default: // Dirlist()
1638  {
1639 
1640  // --------- DIRLIST
1641  memset(&xrdreq, 0, sizeof (ClientRequest));
1643 
1644  std::string s = resourceplusopaque.c_str();
1646  //s += "?xrd.dirstat=1";
1647 
1648  l = s.length() + 1;
1649  xrdreq.dirlist.dlen = htonl(l);
1650 
1651  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1652  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1653  return -1;
1654  }
1655 
1656  // We don't want to be invoked again after this request is finished
1657  return 1;
1658  }
1659  }
1660 
1661 
1662  break;
1663  }
1664  case XrdHttpReq::rtMKCOL:
1665  {
1666 
1667  // --------- MKDIR
1668  memset(&xrdreq, 0, sizeof (ClientRequest));
1669  xrdreq.mkdir.requestid = htons(kXR_mkdir);
1670 
1671  std::string s = resourceplusopaque.c_str();
1673 
1674  l = s.length() + 1;
1675  xrdreq.mkdir.dlen = htonl(l);
1676 
1677  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1678  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1679  return -1;
1680  }
1681 
1682  // We don't want to be invoked again after this request is finished
1683  return 1;
1684  }
1685  case XrdHttpReq::rtMOVE:
1686  {
1687 
1688  // --------- MOVE
1689  memset(&xrdreq, 0, sizeof (ClientRequest));
1690  xrdreq.mv.requestid = htons(kXR_mv);
1691 
1692  std::string s = resourceplusopaque.c_str();
1693  s += " ";
1694 
1695  char buf[256];
1696  char *ppath;
1697  int port = 0;
1698  if (parseURL((char *) destination.c_str(), buf, port, &ppath)) {
1699  prot->SendSimpleResp(501, NULL, NULL, (char *) "Cannot parse destination url.", 0, false);
1700  return -1;
1701  }
1702 
1703  char buf2[256];
1704  strcpy(buf2, host.c_str());
1705  char *pos = strchr(buf2, ':');
1706  if (pos) *pos = '\0';
1707 
1708  // If we are a redirector we enforce that the host field is equal to
1709  // whatever was written in the destination url
1710  //
1711  // If we are a data server instead we cannot enforce anything, we will
1712  // just ignore the host part of the destination
1713  if ((prot->myRole == kXR_isManager) && strcmp(buf, buf2)) {
1714  prot->SendSimpleResp(501, NULL, NULL, (char *) "Only in-place renaming is supported for MOVE.", 0, false);
1715  return -1;
1716  }
1717 
1718 
1719 
1720 
1721  s += ppath;
1722 
1723  l = s.length() + 1;
1724  xrdreq.mv.dlen = htonl(l);
1726 
1727  if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1728  prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1729  return -1;
1730  }
1731 
1732  // We don't want to be invoked again after this request is finished
1733  return 1;
1734 
1735  }
1736  default:
1737  {
1738  prot->SendSimpleResp(501, NULL, NULL, (char *) "Request not supported.", 0, false);
1739  return -1;
1740  }
1741 
1742  }
1743 
1744  return 1;
1745 }
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:1154
kXR_unt16 requestid
Definition: XProtocol.hh:804
struct ClientCloseRequest close
Definition: XProtocol.hh:849
kXR_char fhandle[4]
Definition: XProtocol.hh:805
struct ClientMkdirRequest mkdir
Definition: XProtocol.hh:856
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:850
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_new
Definition: XProtocol.hh:455
@ kXR_retstat
Definition: XProtocol.hh:463
struct ClientOpenRequest open
Definition: XProtocol.hh:858
@ 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:697
struct ClientRmRequest rm
Definition: XProtocol.hh:867
kXR_int32 dlen
Definition: XProtocol.hh:648
struct ClientReadRequest read
Definition: XProtocol.hh:865
struct ClientMvRequest mv
Definition: XProtocol.hh:857
kXR_unt16 requestid
Definition: XProtocol.hh:766
kXR_int32 dlen
Definition: XProtocol.hh:483
struct ClientRmdirRequest rmdir
Definition: XProtocol.hh:868
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:695
@ kXR_mkdirpath
Definition: XProtocol.hh:410
struct ClientStatRequest stat
Definition: XProtocol.hh:871
kXR_int64 offset
Definition: XProtocol.hh:806
struct ClientWriteRequest write
Definition: XProtocol.hh:874
kXR_int32 dlen
Definition: XProtocol.hh:770
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:1218
kXR_unt16 requestid
Definition: XProtocol.hh:706
int kXR_int32
Definition: XPtypes.hh:89
unsigned char kXR_char
Definition: XPtypes.hh:65
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
int parseURL(char *url, char *host, int &port, char **path)
Definition: XrdHttpUtils.cc:77
std::vector< XrdOucIOVec2 > XrdHttpIOList
Definition: XrdHttpUtils.hh:95
#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
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:316
char fhandle[4]
Definition: XrdHttpReq.hh:309
int ReqReadV(const XrdHttpIOList &cl)
Prepare the buffers for sending a readv request.
Definition: XrdHttpReq.cc:387
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:93
std::vector< readahead_list > ralist
Definition: XrdHttpReq.hh:191
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:240
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:926
long fileflags
Definition: XrdHttpReq.hh:306
XrdOucString resourceplusopaque
The resource specified by the request, including all the opaque data.
Definition: XrdHttpReq.hh:244
std::string host
The host field specified in the req.
Definition: XrdHttpReq.hh:260
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum
The checksum that was ran for this request.
Definition: XrdHttpReq.hh:268
bool m_appended_hdr2cgistr
Definition: XrdHttpReq.hh:279
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
Definition: XrdHttpReq.cc:627
XrdOucString m_resource_with_digest
Definition: XrdHttpReq.hh:273
long long filesize
Definition: XrdHttpReq.hh:305
bool readClosing
Definition: XrdHttpReq.hh:252
const char * c_str() const
int erasefromend(int sz=0)
bool endswith(char c)
bool beginswith(char c)
int length() const
void append(const int i)
static std::string obfuscate(const std::string &input, const std::unordered_set< std::string > &keysToObfuscate, const char keyValueDelimiter, const char listDelimiter)
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, 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, XrdOucString::endswith(), XrdOucString::erasefromend(), ClientCloseRequest::fhandle, ClientReadRequest::fhandle, ClientWriteRequest::fhandle, fhandle, fileflags, filesize, fopened, XrdHttpChecksumHandler::getChecksumToRun(), XrdHttpChecksum::getXRootDConfigDigestName(), 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_stat, kXR_ur, kXR_uw, kXR_write, XrdHttpProtocol::StaticPreloadInfo::len, length, XrdOucString::length(), XrdHttpProtocol::listdeny, XrdHttpProtocol::listredir, m_appended_hdr2cgistr, m_req_cksum, m_req_digest, m_resource_with_digest, ClientRequest::mkdir, ClientOpenRequest::mode, ClientRequest::mv, XrdHttpProtocol::myRole, XrdHttpReadRangeHandler::NextReadList(), XrdOucUtils::obfuscate(), ClientReadRequest::offset, ClientWriteRequest::offset, opaque, ClientRequest::open, ClientDirlistRequest::options, ClientMkdirRequest::options, ClientOpenRequest::options, parseBody(), parseURL(), XrdHttpExtHandler::ProcessReq(), quote(), 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, 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 532 of file XrdHttpReq.cc.

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

References appendOpaque(), XrdOucString::c_str(), calcHashes(), XrdHttpProtocol::isdesthttps, keepalive, quote(), 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 387 of file XrdHttpReq.cc.

387  {
388 
389 
390  // Now we build the protocol-ready read ahead list
391  // and also put the correct placeholders inside the cache
392  int n = cl.size();
393  ralist.clear();
394  ralist.reserve(n);
395 
396  int j = 0;
397  for (const auto &c: cl) {
398  ralist.emplace_back();
399  auto &ra = ralist.back();
400  memcpy(&ra.fhandle, this->fhandle, 4);
401 
402  ra.offset = c.offset;
403  ra.rlen = c.size;
404  j++;
405  }
406 
407  if (j > 0) {
408 
409  // Prepare a request header
410 
411  memset(&xrdreq, 0, sizeof (xrdreq));
412 
413  xrdreq.header.requestid = htons(kXR_readv);
414  xrdreq.readv.dlen = htonl(j * sizeof (struct readahead_list));
415 
416  clientMarshallReadAheadList(j);
417 
418 
419  }
420 
421  return (j * sizeof (struct readahead_list));
422 }
struct ClientReadVRequest readv
Definition: XProtocol.hh:866
@ 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 2710 of file XrdHttpReq.cc.

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

References allheaders, depth, destination, etext, filesize, fopened, hdr2cgistr, headerok, host, iovL, iovN, iovP, keepalive, kXR_noErrorYet, kXR_noResponsesYet, length, m_appended_hdr2cgistr, m_digest_header, 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:

◆ userAgent()

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

Definition at line 206 of file XrdHttpReq.hh.

206 {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 237 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ depth

int XrdHttpReq::depth

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

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

◆ etext

std::string XrdHttpReq::etext

Definition at line 295 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 309 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 308 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 306 of file XrdHttpReq.hh.

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

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 307 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 305 of file XrdHttpReq.hh.

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

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 302 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

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

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 301 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

Definition at line 254 of file XrdHttpReq.hh.

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

◆ length

long long XrdHttpReq::length

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

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

Referenced by reset().

◆ m_req_cksum

XrdHttpChecksumHandler::XrdHttpChecksumRawPtr XrdHttpReq::m_req_cksum = nullptr

The checksum that was ran for this request.

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

Referenced by ProcessHTTPReq(), and reset().

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 321 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

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

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 296 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 316 of file XrdHttpReq.hh.

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

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 232 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 233 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

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

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 287 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

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

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 294 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

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

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


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