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 ()
 
void setTransferStatusHeader (std::string &header)
 
const std::string & userAgent () const
 
- Public Member Functions inherited from XrdXrootd::Bridge::Result
 Result ()
 Constructor & Destructor. More...
 
virtual ~Result ()
 
virtual void Free (Bridge::Context &info, char *buffP, int buffL)
 
virtual bool Wait (Bridge::Context &info, int wtime, const char *wtext)
 
virtual Bridge::ResultWaitResp (Bridge::Context &info, int wtime, const char *wtext)
 

Public Attributes

std::map< std::string, std::string > allheaders
 
bool closeAfterError
 
int depth
 
std::string destination
 The destination field specified in the req. More...
 
std::string etext
 
char fhandle [4]
 
long filectime
 
long fileflags
 
long filemodtime
 
long long filesize
 
bool final
 true -> final result More...
 
bool fopened
 
std::string hdr2cgistr
 Additional opaque info that may come from the hdr2cgi directive. More...
 
bool headerok
 Tells if we have finished reading the header. More...
 
std::string host
 The host field specified in the req. More...
 
int iovL
 byte count More...
 
int iovN
 array count More...
 
const struct iovec * iovP
 The latest data chunks got from the xrd layer. These are valid only inside the callbacks! More...
 
bool keepalive
 
long long length
 
bool m_appended_asize {false}
 Track whether we already appended the oss.asize argument for PUTs. More...
 
bool m_appended_hdr2cgistr
 
std::string m_digest_header
 The computed digest for the HTTP response header. More...
 
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 224 of file XrdHttpReq.hh.

224  {
225  rtUnset = -1,
226  rtUnknown = 0,
227  rtMalformed,
228  rtGET,
229  rtHEAD,
230  rtPUT,
231  rtOPTIONS,
232  rtPATCH,
233  rtDELETE,
234  rtPROPFIND,
235  rtMKCOL,
236  rtMOVE,
237  rtPOST
238  };

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 168 of file XrdHttpReq.hh.

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

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

References reset().

+ Here is the call graph for this function:

Member Function Documentation

◆ addCgi()

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

Definition at line 743 of file XrdHttpReq.cc.

743  {
744  if (hdr2cgistr.length() > 0) {
745  hdr2cgistr.append("&");
746  }
747  hdr2cgistr.append(key);
748  hdr2cgistr.append("=");
749  hdr2cgistr.append(value);
750 }
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.
Definition: XrdHttpReq.hh:291

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

635  {
636 
637  int l = 0;
638  char * p = 0;
639  if (opaque)
640  p = opaque->Env(l);
641 
642  if (hdr2cgistr.empty() && (l < 2) && !hash) return;
643 
644  // this works in most cases, except if the url already contains the xrdhttp tokens
645  s = s + "?";
646  if (!hdr2cgistr.empty()) {
647  s += encode_opaque(hdr2cgistr).c_str();
648  }
649  if (p && (l > 1)) {
650  if (!hdr2cgistr.empty()) {
651  s = s + "&";
652  }
653  s = s + encode_opaque(p + 1).c_str();
654  }
655 
656  if (hash) {
657  if (l > 1) s += "&";
658  s += "xrdhttptk=";
659  s += hash;
660 
661  s += "&xrdhttptime=";
662  char buf[256];
663  sprintf(buf, "%lld", (long long) tnow);
664  s += buf;
665 
666  if (secent) {
667  if (secent->name) {
668  s += "&xrdhttpname=";
669  s += encode_str(secent->name).c_str();
670  }
671  }
672 
673  if (secent->vorg) {
674  s += "&xrdhttpvorg=";
675  s += encode_str(secent->vorg).c_str();
676  }
677 
678  if (secent->host) {
679  s += "&xrdhttphost=";
680  s += encode_str(secent->host).c_str();
681  }
682 
683  if (secent->moninfo) {
684  s += "&xrdhttpdn=";
685  s += encode_str(secent->moninfo).c_str();
686  }
687 
688  if (secent->role) {
689  s += "&xrdhttprole=";
690  s += encode_str(secent->role).c_str();
691  }
692 
693  if (secent->grps) {
694  s += "&xrdhttpgrps=";
695  s += encode_str(secent->grps).c_str();
696  }
697 
698  if (secent->endorsements) {
699  s += "&xrdhttpendorsements=";
700  s += encode_str(secent->endorsements).c_str();
701  }
702 
703  if (secent->credslen) {
704  s += "&xrdhttpcredslen=";
705  char buf[16];
706  sprintf(buf, "%d", secent->credslen);
707  s += encode_str(buf).c_str();
708  }
709 
710  if (secent->credslen) {
711  if (secent->creds) {
712  s += "&xrdhttpcreds=";
713  // Apparently this string might be not 0-terminated (!)
714  char *zerocreds = strndup(secent->creds, secent->credslen);
715  if (zerocreds) {
716  s += encode_str(zerocreds).c_str();
717  free(zerocreds);
718  }
719  }
720  }
721  }
722  }
std::string encode_opaque(const std::string &opaque)
std::string encode_str(const std::string &str)
char * Env(int &envlen)
Definition: XrdOucEnv.hh:48
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
int credslen
Length of the 'creds' data.
Definition: XrdSecEntity.hh:78
char * creds
Raw entity credentials or cert.
Definition: XrdSecEntity.hh:77
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
char * endorsements
Protocol specific endorsements.
Definition: XrdSecEntity.hh:75
char * moninfo
Information for monitoring.
Definition: XrdSecEntity.hh:76
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70

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

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

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

◆ buildPartialHdr()

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

Build a partial header for a multipart response.

Definition at line 430 of file XrdHttpReq.cc.

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

◆ buildPartialHdrEnd()

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

Build the closing part for a multipart response.

Definition at line 440 of file XrdHttpReq.cc.

440  {
441  std::ostringstream s;
442 
443  s << "\r\n--" << token << "--\r\n";
444 
445  return s.str();
446 }

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

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

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

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

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

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

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

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

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

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:275
std::string m_req_digest
The requested digest type.
Definition: XrdHttpReq.hh:278
std::map< std::string, std::string > allheaders
Definition: XrdHttpReq.hh:246
void addCgi(const std::string &key, const std::string &value)
Definition: XrdHttpReq.cc:743
bool sendcontinue
Definition: XrdHttpReq.hh:270
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 885 of file XrdHttpReq.cc.

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

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

References appendOpaque(), XrdOucString::c_str(), calcHashes(), encode_opaque(), encode_str(), XrdHttpProtocol::isdesthttps, keepalive, obfuscateAuth(), redirdest, request, reset(), resource, rtGET, XrdHttpProtocol::SecEntity, XrdHttpProtocol::secretkey, and TRACE.

+ Here is the call graph for this function:

◆ ReqReadV()

int XrdHttpReq::ReqReadV ( const XrdHttpIOList cl)

Prepare the buffers for sending a readv request.

Definition at line 393 of file XrdHttpReq.cc.

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

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

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

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

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

◆ setTransferStatusHeader()

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

Definition at line 2062 of file XrdHttpReq.cc.

2062  {
2063  if (m_status_trailer) {
2064  if (header.empty()) {
2065  header += "Trailer: X-Transfer-Status";
2066  } else {
2067  header += "\r\nTrailer: X-Transfer-Status";
2068  }
2069  }
2070 }

◆ userAgent()

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

Definition at line 215 of file XrdHttpReq.hh.

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

Referenced by parseLine(), and reset().

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 265 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ depth

int XrdHttpReq::depth

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

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

◆ etext

std::string XrdHttpReq::etext

Definition at line 310 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 324 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 323 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 321 of file XrdHttpReq.hh.

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

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 322 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 320 of file XrdHttpReq.hh.

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

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 317 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

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

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 316 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

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

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

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

Referenced by ProcessHTTPReq(), and reset().

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 336 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

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

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 311 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 331 of file XrdHttpReq.hh.

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

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 241 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 242 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

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

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 302 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

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

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 309 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

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

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


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