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

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

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 166 of file XrdHttpReq.hh.

166  :
167  readRangeHandler(rcfg), keepalive(true) {
168 
169  prot = protinstance;
170  length = 0;
171  //xmlbody = 0;
172  depth = 0;
173  opaque = 0;
174  writtenbytes = 0;
175  fopened = false;
176  headerok = false;
177  mScitag = -1;
178  };
bool keepalive
Definition: XrdHttpReq.hh:258
long long length
Definition: XrdHttpReq.hh:259
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:252
long long writtenbytes
In a long write, we track where we have arrived.
Definition: XrdHttpReq.hh:325
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:246
bool fopened
Definition: XrdHttpReq.hh:316
XrdHttpReadRangeHandler readRangeHandler
Tracking the next ranges of data to read during GET.
Definition: XrdHttpReq.hh:255

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

◆ ~XrdHttpReq()

XrdHttpReq::~XrdHttpReq ( )
virtual

Definition at line 110 of file XrdHttpReq.cc.

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

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

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

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

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

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

◆ buildPartialHdrEnd()

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

Build the closing part for a multipart response.

Definition at line 435 of file XrdHttpReq.cc.

435  {
436  std::ostringstream s;
437 
438  s << "\r\n--" << token << "--\r\n";
439 
440  return s.str();
441 }

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

449  {
450 
451  TRACE(REQ, " XrdHttpReq::Data! final=" << final);
452 
453  this->xrdresp = kXR_ok;
454  this->iovP = iovP_;
455  this->iovN = iovN_;
456  this->iovL = iovL_;
457  this->final = final_;
458 
459  if (PostProcessHTTPReq(final_)) reset();
460 
461  return true;
462 
463 };
@ 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:299
int iovL
byte count
Definition: XrdHttpReq.hh:307
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
Definition: XrdHttpReq.hh:305
int iovN
array count
Definition: XrdHttpReq.hh:306

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

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

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

509  {
510 
511  TRACE(REQ, " XrdHttpReq::Error");
512 
513  xrdresp = kXR_error;
514  xrderrcode = (XErrorCode) ecode;
515 
516  if (etext_) {
517  char *s = escapeXML(etext_);
518  this->etext = s;
519  free(s);
520  }
521 
522  if (PostProcessHTTPReq()) reset();
523 
524  // If we are servicing a GET on a directory, it'll generate an error for the default
525  // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
526  // generate a directory listing (if configured).
527  if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
528  return true;
529 
530  return false;
531 };
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:301
ReqType request
The request we got.
Definition: XrdHttpReq.hh:236
XErrorCode xrderrcode
Definition: XrdHttpReq.hh:300
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:296

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

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

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

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

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

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

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

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

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

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

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

2752  {
2753 
2754  TRACE(REQ, " XrdHttpReq request ended.");
2755 
2756  //if (xmlbody) xmlFreeDoc(xmlbody);
2758  readClosing = false;
2759  writtenbytes = 0;
2760  etext.clear();
2761  redirdest = "";
2762 
2763  // // Here we should deallocate this
2764  // const struct iovec *iovP //!< pointer to data array
2765  // int iovN, //!< array count
2766  // int iovL, //!< byte count
2767  // bool final //!< true -> final result
2768 
2769 
2770  //xmlbody = 0;
2771  depth = 0;
2774  ralist.clear();
2775  ralist.shrink_to_fit();
2776 
2777  request = rtUnset;
2778  resource = "";
2779  allheaders.clear();
2780 
2781  // Reset the state of the request's digest request.
2782  m_req_digest.clear();
2783  m_digest_header.clear();
2784  m_req_cksum = nullptr;
2785 
2787  m_user_agent = "";
2788 
2789  headerok = false;
2790  keepalive = true;
2791  length = 0;
2792  filesize = 0;
2793  depth = 0;
2794  sendcontinue = false;
2795 
2796  m_transfer_encoding_chunked = false;
2797  m_current_chunk_size = -1;
2798  m_current_chunk_offset = 0;
2799 
2800  m_trailer_headers = false;
2801  m_status_trailer = false;
2802 
2804  reqstate = 0;
2805 
2806  memset(&xrdreq, 0, sizeof (xrdreq));
2807  memset(&xrdresp, 0, sizeof (xrdresp));
2809 
2810  etext.clear();
2811  redirdest = "";
2812 
2813  stringresp = "";
2814 
2815  host = "";
2816  destination = "";
2817  hdr2cgistr = "";
2818  m_appended_hdr2cgistr = false;
2819  m_appended_asize = false;
2820 
2821  iovP = 0;
2822  iovN = 0;
2823  iovL = 0;
2824 
2825 
2826  if (opaque) delete(opaque);
2827  opaque = 0;
2828 
2829  fopened = false;
2830 
2831  final = false;
2832 
2833  mScitag = -1;
2834 }
@ 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:279
std::string stringresp
If we want to give a string as a response, we compose it here.
Definition: XrdHttpReq.hh:319

References allheaders, 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_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 210 of file XrdHttpReq.hh.

210 {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 241 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ depth

int XrdHttpReq::depth

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

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

◆ etext

std::string XrdHttpReq::etext

Definition at line 301 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 315 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 314 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 312 of file XrdHttpReq.hh.

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

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 313 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 311 of file XrdHttpReq.hh.

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

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 308 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

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

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 307 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

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

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

Definition at line 283 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 279 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 272 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 269 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 277 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 327 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

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

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 302 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 322 of file XrdHttpReq.hh.

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

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 236 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 237 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

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

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 293 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

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

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 300 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

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

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


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