XRootD
Loading...
Searching...
No Matches
XrdHttpReq Class Reference

#include <XrdHttpReq.hh>

Inheritance diagram for XrdHttpReq:
Collaboration diagram for XrdHttpReq:

Public Types

enum  ReqType : int {
  rtUnset = -1 ,
  rtUnknown = 0 ,
  rtMalformed ,
  rtGET ,
  rtHEAD ,
  rtPUT ,
  rtOPTIONS ,
  rtPATCH ,
  rtDELETE ,
  rtPROPFIND ,
  rtMKCOL ,
  rtMOVE ,
  rtPOST ,
  rtCOPY ,
  rtCount
}
 These are the HTTP/DAV requests that we support. More...

Public Member Functions

 XrdHttpReq (XrdHttpProtocol *protinstance, const XrdHttpReadRangeHandler::Configuration &rcfg)
virtual ~XrdHttpReq ()
void addCgi (const std::string &key, const std::string &value)
void appendOpaque (XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
std::string buildPartialHdr (long long bytestart, long long byteend, long long filesize, char *token)
 Build a partial header for a multipart response.
std::string buildPartialHdrEnd (char *token)
 Build the closing part for a multipart response.
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
virtual bool Error (XrdXrootd::Bridge::Context &info, int ecode, const char *etext)
virtual int File (XrdXrootd::Bridge::Context &info, int dlen)
int getHttpStatusCode ()
int getInitialStatusCode ()
int parseBody (char *body, long long len)
 Parse the body of a request, assuming that it's XML and that it's entirely in memory.
int parseFirstLine (char *line, int len)
 Parse the first line of the header.
int parseLine (char *line, int len)
 Parse the header.
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.
virtual void reset ()
void setHttpStatusCode (int code)
void setTransferStatusHeader (std::string &header)
const std::string & userAgent () const
Public Member Functions inherited from XrdXrootd::Bridge::Result
 Result ()
 Constructor & Destructor.
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::Result * WaitResp (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.
long long etagval
std::string etext
char fhandle [4]
long filectime
long fileflags
long filemodtime
long long filesize
bool final
 true -> final result
bool fopened
std::string hdr2cgistr
 Additional opaque info that may come from the hdr2cgi directive.
bool headerok
 Tells if we have finished reading the header.
std::string host
 The host field specified in the req.
int iovL
 byte count
int iovN
 array count
const struct iovec * iovP
 The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
bool keepalive
ssize_t length
bool length_seen {false}
bool m_appended_asize {false}
 Track whether we already appended the oss.asize argument for PUTs.
bool m_appended_hdr2cgistr
std::string m_digest_header
 The computed digest for the HTTP response header.
std::string m_origin
std::map< std::string, std::string > m_repr_digest
 Repr-Digest map where the key is the digest name and the value is the base64 encoded digest value.
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum = nullptr
 The checksum that was ran for this request.
XrdOucString m_resource_with_digest
std::string m_want_digest
 The requested digest type.
std::map< std::string, uint8_t > m_want_repr_digest
XrdHttpMonState monState
int mScitag
XrdOucEnv * opaque
 The opaque data, after parsing.
std::vector< readahead_list > ralist
bool readClosing
XrdHttpReadRangeHandler readRangeHandler
 Tracking the next ranges of data to read during GET.
XrdOucString redirdest
int reqstate
 State machine to talk to the bridge.
ReqType request
 The request we got.
std::string requestverb
XrdOucString resource
 The resource specified by the request, stripped of opaque data.
XrdOucString resourceplusopaque
 The resource specified by the request, including all the opaque data.
unsigned int rwOpDone
 To coordinate multipart responses across multiple calls.
unsigned int rwOpPartialDone
bool sendcontinue
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::time_point::min()
std::string stringresp
 If we want to give a string as a response, we compose it here.
long long writtenbytes
 In a long write, we track where we have arrived.
XErrorCode xrderrcode
ClientRequest xrdreq
 The last issued xrd request, often pending.
XResponseType xrdresp
 The last response data we got.

Detailed Description

Definition at line 66 of file XrdHttpReq.hh.

Member Enumeration Documentation

◆ ReqType

enum XrdHttpReq::ReqType : int

These are the HTTP/DAV requests that we support.

Enumerator
rtUnset 
rtUnknown 
rtMalformed 
rtGET 
rtHEAD 
rtPUT 
rtOPTIONS 
rtPATCH 
rtDELETE 
rtPROPFIND 
rtMKCOL 
rtMOVE 
rtPOST 
rtCOPY 
rtCount 

Definition at line 77 of file XrdHttpReq.hh.

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 208 of file XrdHttpReq.hh.

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

References closeAfterError, depth, fopened, headerok, keepalive, length, mScitag, opaque, readRangeHandler, and writtenbytes.

◆ ~XrdHttpReq()

XrdHttpReq::~XrdHttpReq ( )
virtual

Definition at line 112 of file XrdHttpReq.cc.

112 {
113 //if (xmlbody) xmlFreeDoc(xmlbody);
114
115 reset();
116}
virtual void reset()

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

823 {
824 if (hdr2cgistr.length() > 0) {
825 hdr2cgistr.append("&");
826 }
827 hdr2cgistr.append(key);
828 hdr2cgistr.append("=");
829 hdr2cgistr.append(value);
830}
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.

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

715 {
716
717 int l = 0;
718 char * p = 0;
719 if (opaque)
720 p = opaque->Env(l);
721
722 if (hdr2cgistr.empty() && (l < 2) && !hash) return;
723
724 // this works in most cases, except if the url already contains the xrdhttp tokens
725 s = s + "?";
726 if (!hdr2cgistr.empty()) {
727 s += encode_opaque(hdr2cgistr).c_str();
728 }
729 if (p && (l > 1)) {
730 if (!hdr2cgistr.empty()) {
731 s = s + "&";
732 }
733 s = s + encode_opaque(p + 1).c_str();
734 }
735
736 if (hash) {
737 if (l > 1) s += "&";
738 s += "xrdhttptk=";
739 s += hash;
740
741 s += "&xrdhttptime=";
742 char buf[256];
743 sprintf(buf, "%lld", (long long) tnow);
744 s += buf;
745
746 if (secent) {
747 if (secent->name) {
748 s += "&xrdhttpname=";
749 s += encode_str(secent->name).c_str();
750 }
751 }
752
753 if (secent->vorg) {
754 s += "&xrdhttpvorg=";
755 s += encode_str(secent->vorg).c_str();
756 }
757
758 if (secent->host) {
759 s += "&xrdhttphost=";
760 s += encode_str(secent->host).c_str();
761 }
762
763 if (secent->moninfo) {
764 s += "&xrdhttpdn=";
765 s += encode_str(secent->moninfo).c_str();
766 }
767
768 if (secent->role) {
769 s += "&xrdhttprole=";
770 s += encode_str(secent->role).c_str();
771 }
772
773 if (secent->grps) {
774 s += "&xrdhttpgrps=";
775 s += encode_str(secent->grps).c_str();
776 }
777
778 if (secent->endorsements) {
779 s += "&xrdhttpendorsements=";
780 s += encode_str(secent->endorsements).c_str();
781 }
782
783 if (secent->credslen) {
784 s += "&xrdhttpcredslen=";
785 char buf[16];
786 sprintf(buf, "%d", secent->credslen);
787 s += encode_str(buf).c_str();
788 }
789
790 if (secent->credslen) {
791 if (secent->creds) {
792 s += "&xrdhttpcreds=";
793 // Apparently this string might be not 0-terminated (!)
794 char *zerocreds = strndup(secent->creds, secent->credslen);
795 if (zerocreds) {
796 s += encode_str(zerocreds).c_str();
797 free(zerocreds);
798 }
799 }
800 }
801 }
802 }
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).
int credslen
Length of the 'creds' data.
char * creds
Raw entity credentials or cert.
char * grps
Entity's group name(s).
char * name
Entity's name.
char * role
Entity's role(s).
char * endorsements
Protocol specific endorsements.
char * moninfo
Information for monitoring.
char * host
Entity's host name dnr dependent.

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

488 {
489 std::ostringstream s;
490
491 s << "\r\n--" << token << "\r\n";
492 s << "Content-type: text/plain; charset=UTF-8\r\n";
493 s << "Content-range: bytes " << bytestart << "-" << byteend << "/" << fsz << "\r\n\r\n";
494
495 return s.str();
496}

◆ buildPartialHdrEnd()

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

Build the closing part for a multipart response.

Definition at line 498 of file XrdHttpReq.cc.

498 {
499 std::ostringstream s;
500
501 s << "\r\n--" << token << "--\r\n";
502
503 return s.str();
504}

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

512 {
513
514 TRACE(REQ, " XrdHttpReq::Data! final=" << final);
515
516 this->xrdresp = kXR_ok;
517 this->iovP = iovP_;
518 this->iovN = iovN_;
519 this->iovL = iovL_;
520 this->final = final_;
521
522 if (PostProcessHTTPReq(final_)) reset();
523
524 return true;
525
526};
@ kXR_ok
Definition XProtocol.hh:941
#define TRACE(act, x)
Definition XrdTrace.hh:63
XResponseType xrdresp
The last response data we got.
int iovL
byte count
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
int iovN
array count

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

552 {
553
554 TRACE(REQ, " XrdHttpReq::Done");
555
556 xrdresp = kXR_ok;
557
558 this->iovN = 0;
559
560 int r = PostProcessHTTPReq(true);
561 // Beware, we don't have to reset() if the result is 0
562 if (r) reset();
563 if (r < 0) return false;
564
565
566 return true;
567};

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

572 {
573
574 TRACE(REQ, " XrdHttpReq::Error");
575
577 xrderrcode = (XErrorCode) ecode;
578
579 if (etext_) {
580 char *s = escapeXML(etext_);
581 this->etext = s;
582 free(s);
583 }
584
585 auto rc = PostProcessHTTPReq();
586 if (rc) {
587 reset();
588 }
589
590 // If we are servicing a GET on a directory, it'll generate an error for the default
591 // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
592 // generate a directory listing (if configured).
593 if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
594 return true;
595
596 return rc == 0;
597};
XErrorCode
@ kXR_isDirectory
@ kXR_error
Definition XProtocol.hh:945
struct ClientRequestHdr header
Definition XProtocol.hh:887
kXR_unt16 requestid
Definition XProtocol.hh:159
@ kXR_open
Definition XProtocol.hh:123
char * escapeXML(const char *str)
std::string etext
ReqType request
The request we got.
XErrorCode xrderrcode
ClientRequest xrdreq
The last issued xrd request, often pending.

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

530 {
531
532 // sendfile about to be sent by bridge for fetching data for GET:
533 // no https, no chunked+trailer, no multirange
534
535 //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen);
536 int rc = info.Send(0, 0, 0, 0);
537 TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc);
538 bool start, finish;
539 // short read will be classed as error
540 if (rc) {
542 return false;
543 }
544
545 if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
546 return false;
547
548
549 return true;
550};
void NotifyError()
Force handler to enter error state.
int NotifyReadResult(const ssize_t ret, const UserRange **const urp, bool &start, bool &allend)
Advance internal counters concerning received bytes.
virtual int Send(const struct iovec *headP, int headN, const struct iovec *tailP, int tailN)

References XrdHttpReadRangeHandler::NotifyError(), XrdHttpReadRangeHandler::NotifyReadResult(), readRangeHandler, XrdXrootd::Bridge::Context::Send(), and TRACE.

Here is the call graph for this function:

◆ getHttpStatusCode()

int XrdHttpReq::getHttpStatusCode ( )
inline

Definition at line 227 of file XrdHttpReq.hh.

227{ return httpStatusCode;}

◆ getInitialStatusCode()

int XrdHttpReq::getInitialStatusCode ( )
inline

Definition at line 226 of file XrdHttpReq.hh.

226{ return initialStatusCode;}

◆ parseBody()

int XrdHttpReq::parseBody ( char * body,
long long len )

Parse the body of a request, assuming that it's XML and that it's entirely in memory.

Definition at line 96 of file XrdHttpReq.cc.

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

Referenced by ProcessHTTPReq().

Here is the caller graph for this function:

◆ parseFirstLine()

int XrdHttpReq::parseFirstLine ( char * line,
int len )

Parse the first line of the header.

Definition at line 319 of file XrdHttpReq.cc.

319 {
320
321 char *key = line;
322
323 int pos;
324
325 // Do the naive parsing
326 if (!line) return -1;
327
328 // Look for the first space-delimited token
329 char *p = strchr((char *) line, (int) ' ');
330 if (!p) {
332 return -1;
333 }
334
335
336 pos = p - line;
337 // The first token cannot be too long
338 if (pos > MAX_TK_LEN - 1) {
340 return -2;
341 }
342
343 // The first space-delimited char cannot be the first one
344 // this allows to deal with the case when a client sends a first line that starts with a space " GET / HTTP/1.1"
345 if(pos == 0) {
347 return -4;
348 }
349
350 // the first token must be non empty
351 if (pos > 0) {
352 line[pos] = 0;
353 char *val = line + pos + 1;
354
355 // Here we are supposed to initialize whatever flag or variable that is needed
356 // by looking at the first token of the line
357
358 // The token is key
359 // The remainder is val, look for the resource
360 p = strchr((char *) val, (int) ' ');
361
362 if (!p) {
364 line[pos] = ' ';
365 return -3;
366 }
367
368 *p = '\0';
369 parseResource(val);
370
371 *p = ' ';
372
373 // Xlate the known header lines
374 if (!strcmp(key, "GET")) {
375 request = rtGET;
376 } else if (!strcmp(key, "HEAD")) {
377 request = rtHEAD;
378 } else if (!strcmp(key, "PUT")) {
379 request = rtPUT;
380 } else if (!strcmp(key, "POST")) {
381 request = rtPOST;
382 } else if (!strcmp(key, "PATCH")) {
384 } else if (!strcmp(key, "OPTIONS")) {
386 } else if (!strcmp(key, "DELETE")) {
388 } else if (!strcmp(key, "PROPFIND")) {
390 } else if (!strcmp(key, "MKCOL")) {
392 } else if (!strcmp(key, "MOVE")) {
393 request = rtMOVE;
394 } else if (!strcmp(key, "COPY")) {
395 request = rtCOPY;
396 } else {
398 }
399
400 requestverb = key;
401
402 // The last token should be the protocol. If it is HTTP/1.0, then
403 // keepalive is disabled by default.
404 if (!strcmp(p+1, "HTTP/1.0\r\n")) {
405 keepalive = false;
406 }
407 line[pos] = ' ';
408 }
409
410 return 0;
411}
#define MAX_TK_LEN
Definition XrdHttpReq.cc:67
std::string requestverb

References keepalive, MAX_TK_LEN, request, requestverb, rtCOPY, rtDELETE, rtGET, rtHEAD, rtMalformed, rtMKCOL, rtMOVE, rtOPTIONS, rtPATCH, rtPOST, rtPROPFIND, rtPUT, and rtUnknown.

Referenced by XrdHttpProtocol::Process().

Here is the caller graph for this function:

◆ parseLine()

int XrdHttpReq::parseLine ( char * line,
int len )

Parse the header.

Definition at line 118 of file XrdHttpReq.cc.

118 {
119
120 char *key = line;
121 int pos;
122
123 // Do the parsing
124 if (!line) return -1;
125
126
127 char *p = strchr((char *) line, (int) ':');
128 if (!p) {
129
131 return -1;
132 }
133
134 pos = (p - line);
135 if (pos > (MAX_TK_LEN - 1)) {
136
138 return -2;
139 }
140
141 if (pos > 0) {
142 line[pos] = 0;
143 char *val = line + pos + 1;
144
145 // Trim left
146 while ( (!isgraph(*val) || (!*val)) && (val < line+len)) val++;
147
148 // We memorize the headers also as a string
149 // because external plugins may need to process it differently
150 std::string ss = val;
151 if(ss.length() >= 2 && ss.substr(ss.length() - 2, 2) != "\r\n") {
153 return -3;
154 }
155 trim(ss);
156 allheaders[key] = ss;
157
158 // Here we are supposed to initialize whatever flag or variable that is needed
159 // by looking at the first token of the line
160 // The token is key
161 // The value is val
162
163 // Screen out the needed header lines
164 if (!strcasecmp(key, "connection")) {
165
166 if (!strcasecmp(val, "Keep-Alive\r\n")) {
167 keepalive = true;
168 } else if (!strcasecmp(val, "close\r\n")) {
169 keepalive = false;
170 }
171
172 } else if (!strcasecmp(key, "host")) {
173 parseHost(val);
174 } else if (!strcasecmp(key, "range")) {
175 // (rfc2616 14.35.1) says if Range header contains any range
176 // which is syntactically invalid the Range header should be ignored.
177 // Therefore no need for the range handler to report an error.
179 } else if (!strcasecmp(key, "content-length")) {
180 // Parse and validate the Content-Length value (one-or-more digits,
181 // no sign, no embedded garbage, no overflow). Anything malformed
182 // gives the server an ambiguous body length and is an HTTP request
183 // smuggling primitive — reject with HTTP 400.
184 // Reference: RFC 9112 §6.2, RFC 7230 §3.3.3 rule 4.
185 ssize_t parsed = XrdHttpHeaderUtils::parseContentLength(val);
186 if (parsed < 0) {
188 return -6;
189 }
190 if (m_transfer_encoding_chunked) {
191 // A request that already declared Transfer-Encoding: chunked and
192 // now also sends Content-Length is the classic smuggling vector
193 // (the frontend and backend may disagree on which header wins).
194 // Reference: RFC 9112 §6.1.
196 return -8;
197 }
198 if (length_seen && parsed != length) {
199 // Two Content-Length headers with different values. The body
200 // length is ambiguous; reject.
201 // Reference: RFC 7230 §3.3.3 rule 4.
203 return -7;
204 }
205 length = parsed;
206 length_seen = true;
207
208 } else if (!strcasecmp(key, "destination")) {
209 destination.assign(val, line+len-val);
211 } else if (!strcasecmp(key, "want-digest")) {
212 // Discard Want-Repr-Digest in favor of Want-Digest
213 m_want_repr_digest.clear();
214 m_want_digest.assign(val, line + len - val);
216 //Transform the user requests' want-digest to lowercase
217 std::transform(m_want_digest.begin(), m_want_digest.end(), m_want_digest.begin(), ::tolower);
218 } else if (!strcasecmp(key, "depth")) {
219 depth = -1;
220 if (strcmp(val, "infinity"))
221 depth = atoll(val);
222
223 } else if (!strcasecmp(key, "expect") && strstr(val, "100-continue")) {
224 sendcontinue = true;
225 } else if (!strcasecmp(key, "te") && strstr(val, "trailers")) {
226 m_trailer_headers = true;
227 } else if (!strcasecmp(key, "transfer-encoding")) {
228 // Tokenize the Transfer-Encoding list and verify that "chunked"
229 // is present AND is the final encoding. Anything else (substring
230 // matches like "chunkedX", a non-final "chunked", or only unknown
231 // codings) is rejected so a frontend proxy cannot disagree with us
232 // about how the body is framed.
233 // Reference: RFC 9112 §6.1, RFC 7230 §3.3.1.
236 return -4;
237 }
238 if (length_seen) {
239 // Content-Length was already accepted and now Transfer-Encoding:
240 // chunked arrives. Reject (see the matching check in the
241 // Content-Length branch above).
242 // Reference: RFC 9112 §6.1.
244 return -8;
245 }
246 m_transfer_encoding_chunked = true;
247 } else if (!strcasecmp(key, "x-transfer-status") && strstr(val, "true")) {
248 m_transfer_encoding_chunked = true;
249 m_status_trailer = true;
250 } else if (!strcasecmp(key, "scitag")) {
251 if(prot->pmarkHandle != nullptr) {
252 parseScitag(val);
253 }
254 } else if (!strcasecmp(key, "user-agent")) {
255 m_user_agent = val;
256 trim(m_user_agent);
257 } else if (!strcasecmp(key,"origin")) {
258 m_origin = val;
259 trim(m_origin);
260 } else if (!strcasecmp(key,"repr-digest")) {
262 } else if (!strcasecmp(key,"want-repr-digest")) {
263 if(m_want_digest.empty()) {
264 // If Want-Digest was set, don't parse want-repr-digest
266 }
267 } else {
268 // Some headers need to be translated into "local" cgi info.
269 auto it = std::find_if(prot->hdr2cgimap.begin(), prot->hdr2cgimap.end(),[key](const auto & item) {
270 return !strcasecmp(key,item.first.c_str());
271 });
272 if (it != prot->hdr2cgimap.end() && (opaque ? (0 == opaque->Get(it->second.c_str())) : true)) {
273 std::string s;
274 s.assign(val, line+len-val);
275 trim(s);
276 addCgi(it->second,s);
277 }
278 }
279
280
281 line[pos] = ':';
282 }
283
284 return 0;
285}
void trim(std::string &str)
Definition XrdHttpReq.cc:78
static int parseTransferEncoding(const std::string &value)
static void parseWantReprDigest(const std::string &value, std::map< std::string, uint8_t > &output)
static void parseReprDigest(const std::string &value, std::map< std::string, std::string > &output)
static ssize_t parseContentLength(const std::string &value)
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.
std::map< std::string, uint8_t > m_want_repr_digest
std::map< std::string, std::string > m_repr_digest
Repr-Digest map where the key is the digest name and the value is the base64 encoded digest value.
bool length_seen
std::string m_origin
std::string m_want_digest
The requested digest type.
std::map< std::string, std::string > allheaders
void addCgi(const std::string &key, const std::string &value)
bool sendcontinue
char * Get(const char *varname)
Definition XrdOucEnv.hh:69

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

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

References XrdOucEnv::XrdOucEnv(), allheaders, XrdOucString::append(), appendOpaque(), ClientMvRequest::arg1len, XrdOucString::beginswith(), XrdOucString::c_str(), XrdOucTUtils::caseInsensitiveFind(), ClientRequest::close, closeAfterError, XrdHttpProtocol::StaticPreloadInfo::data, DEBUG, depth, destination, ClientRequest::dirlist, ClientDirlistRequest::dlen, ClientMkdirRequest::dlen, ClientMvRequest::dlen, ClientOpenRequest::dlen, ClientReadRequest::dlen, ClientRmdirRequest::dlen, ClientRmRequest::dlen, ClientStatRequest::dlen, ClientWriteRequest::dlen, encode_opaque(), encode_str(), XrdOucString::endswith(), XrdOucString::erasefromend(), ClientCloseRequest::fhandle, ClientReadRequest::fhandle, ClientWriteRequest::fhandle, fhandle, fileflags, filesize, XrdOucString::find(), fopened, XrdHttpReadRangeHandler::getMaxRanges(), hdr2cgistr, host, XrdHttpReadRangeHandler::isSingleRange(), keepalive, kXR_close, kXR_delete, kXR_dirlist, kXR_dstat, kXR_gr, kXR_gw, kXR_isDir, kXR_isManager, kXR_mkdir, kXR_mkdirpath, kXR_mkpath, kXR_mv, kXR_new, kXR_open, kXR_open_read, kXR_open_wrto, kXR_or, kXR_read, kXR_retstat, kXR_rm, kXR_rmdir, kXR_seqio, kXR_stat, kXR_ur, kXR_uw, kXR_write, XrdHttpProtocol::StaticPreloadInfo::len, length, XrdOucString::length(), m_appended_asize, m_appended_hdr2cgistr, m_req_cksum, m_resource_with_digest, m_want_digest, m_want_repr_digest, ClientRequest::mkdir, ClientOpenRequest::mode, ClientRequest::mv, XrdHttpReadRangeHandler::NextReadList(), obfuscateAuth(), ClientReadRequest::offset, ClientWriteRequest::offset, opaque, ClientRequest::open, ClientDirlistRequest::options, ClientMkdirRequest::options, ClientOpenRequest::options, parseBody(), ProcessHTTPReq(), XrdHttpExtHandler::ProcessReq(), ralist, ClientRequest::read, readClosing, readRangeHandler, ReqReadV(), reqstate, request, ClientCloseRequest::requestid, ClientDirlistRequest::requestid, ClientMkdirRequest::requestid, ClientMvRequest::requestid, ClientOpenRequest::requestid, ClientReadRequest::requestid, ClientRmdirRequest::requestid, ClientRmRequest::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, sendcontinue, startTime, ClientRequest::stat, STR_NPOS, TRACE, TRACE_DEBUG, TRACEI, TRACING, ClientRequest::write, writtenbytes, and xrdreq.

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

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 (or absolute URL).

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

Parameters
infothe context associated with the result.
portdestination port in host byte order; when port < 0 and hname is an absolute URL (scheme://…), Location is that URL as-is (path included) and the original resource is not appended. Otherwise Location is built as http(s)://hname[:port]<resource>.
hnameDNS name / IP, or absolute URL when port < 0.
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 599 of file XrdHttpReq.cc.

602 {
603
604
605
606 char hash[512];
607 hash[0] = '\0';
608
609 bool invalid_host = false;
610
611 if (!hname) {
612 invalid_host = true;
613 } else {
614 for (const char *c = hname; *c; ++c)
615 if (*c == '\r' || *c == '\n')
616 invalid_host = true;
617 }
618
619 if (invalid_host) {
620 prot->SendSimpleResp(502, nullptr, nullptr, "Invalid redirect host", 0, false);
621 return keepalive;
622 }
623
624 // port < 0 means XRootD URL-form redirect: hname is a full scheme://… URL
625 // (host+port+path).
626 // Do not prefix http(s):// and do not append the original resource
627 // otherwise, that would produce https://https://…/pfn/lfn.
628 const bool fullUrl = (port < 0);
629 if (fullUrl) {
630 TRACE(REQ, " XrdHttpReq::Redir using absolute URL: " << hname);
631 }
632
633 // Beware, certain Ofs implementations (e.g. EOS) add opaque data directly to the host name
634 // This must be correctly treated here and appended to the opaque info
635 // that we may already have
636 char *pp = strchr((char *)hname, '?');
637 char *vardata = 0;
638 if (pp) {
639 *pp = '\0';
640 vardata = pp+1;
641 int varlen = strlen(vardata);
642
643 //Now extract the remaining, vardata points to it
644 while(*vardata == '&' && varlen) {vardata++; varlen--;}
645 }
646
647 // If the destination speaks cleartext HTTP, it needs the
648 // secret hash to reconstruct authorization info.
649 const bool destHttpCleartext =
650 fullUrl ? (strncmp(hname, "http://", 7) == 0) : (!prot->isdesthttps);
651
652 std::string urlHashPath;
653 {
654 const std::string encodedResource =
655 fullUrl ? std::string() : encode_str(resource.c_str());
656 redirdest = httpBuildRedirectLocation(prot->isdesthttps, port, hname,
657 encodedResource.c_str()).c_str();
658
659 // Derive the token path while hname is still truncated at '?', so the CGI
660 // stays out of the hash and both ends digest the same string.
661 if (fullUrl && destHttpCleartext)
663 }
664
665 // Restore '?' so later uses of hname see the original string.
666 if (pp)
667 *pp = '?';
668
669 // Here we put back the opaque info, if any
670 if (vardata) {
671 redirdest += "?&";
672 redirdest += encode_opaque(vardata).c_str();
673 }
674
675 // Shall we put also the opaque data of the request? Maybe not
676 //int l;
677 //if (opaque && opaque->Env(l))
678 // redirdest += opaque->Env(l);
679
680
681 time_t timenow = 0;
682 if (destHttpCleartext && prot->ishttps) {
683 const char *hashPath = urlHashPath.empty() ? resource.c_str() : urlHashPath.c_str();
684 // If the destination is not https, then we suppose that it
685 // will need this token to fill its authorization info
686 timenow = time(0);
687 calcHashes(hash, hashPath, (kXR_int16) request,
688 &prot->SecEntity,
689 timenow,
690 prot->secretkey);
691 }
692
693 if (hash[0]) {
694 appendOpaque(redirdest, &prot->SecEntity, hash, timenow);
695 } else
696 appendOpaque(redirdest, 0, 0, 0);
697
698 if (!prot->strp_cgi_params.empty()) {
699 stripCgi(redirdest, prot->strp_cgi_params); /* appendOpaque() may have added credentials */
700 }
701
702 TRACE(REQ, " XrdHttpReq::Redir Redirecting to " << redirdest.c_str());
703
704 if (request != rtGET)
705 prot->SendSimpleResp(307, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
706 else
707 prot->SendSimpleResp(302, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
708
709 bool ret_keepalive = keepalive; // reset() clears keepalive
710 reset();
711 return ret_keepalive;
712};
std::string httpCollapseSlashes(std::string path)
std::string httpPathFromAbsoluteUrl(const char *hname)
Path starting at the first / after the authority. An absent path is /.
std::string httpBuildRedirectLocation(bool destHttps, int port, const char *hname, const char *encodedResource)
std::string decode_str(const std::string &str)
void stripCgi(std::string &url, const std::unordered_set< std::string > &cgiKeys)
if(ec< 0) ec
XrdOucString redirdest

References appendOpaque(), XrdOucString::c_str(), calcHashes(), decode_str(), encode_opaque(), encode_str(), httpBuildRedirectLocation(), httpCollapseSlashes(), httpPathFromAbsoluteUrl(), keepalive, redirdest, request, reset(), resource, rtGET, stripCgi(), 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 451 of file XrdHttpReq.cc.

451 {
452
453
454 // Now we build the protocol-ready read ahead list
455 // and also put the correct placeholders inside the cache
456 int n = cl.size();
457 ralist.clear();
458 ralist.reserve(n);
459
460 int j = 0;
461 for (const auto &c: cl) {
462 ralist.emplace_back();
463 auto &ra = ralist.back();
464 memcpy(&ra.fhandle, this->fhandle, 4);
465
466 ra.offset = c.offset;
467 ra.rlen = c.size;
468 j++;
469 }
470
471 if (j > 0) {
472
473 // Prepare a request header
474
475 memset(&xrdreq, 0, sizeof (xrdreq));
476
478 xrdreq.readv.dlen = htonl(j * sizeof (struct readahead_list));
479
480 clientMarshallReadAheadList(j);
481
482
483 }
484
485 return (j * sizeof (struct readahead_list));
486}
struct ClientReadVRequest readv
Definition XProtocol.hh:910
@ kXR_readv
Definition XProtocol.hh:138

References ClientReadVRequest::dlen, ClientRequest::header, kXR_readv, ralist, ClientRequest::readv, ClientRequestHdr::requestid, and xrdreq.

Referenced by ProcessHTTPReq().

Here is the caller graph for this function:

◆ reset()

void XrdHttpReq::reset ( )
virtual

State machine to talk to the bridge

Definition at line 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_want_digest.clear();
2794 m_digest_header.clear();
2795 m_req_cksum = nullptr;
2796
2797 m_user_agent = "";
2798 m_origin = "";
2799
2800 httpStatusCode = -1;
2801 initialStatusCode= -1;
2802 httpErrorCode = "";
2803 httpErrorBody = "";
2804
2805 headerok = false;
2806 keepalive = true;
2807 length = 0;
2808 length_seen = false;
2809 filesize = 0;
2810 depth = 0;
2811 sendcontinue = false;
2812
2813 m_transfer_encoding_chunked = false;
2814 m_current_chunk_size = -1;
2815 m_current_chunk_offset = 0;
2816
2817 m_trailer_headers = false;
2818 m_status_trailer = false;
2819
2821 reqstate = 0;
2822
2823 memset(&xrdreq, 0, sizeof (xrdreq));
2824 memset(&xrdresp, 0, sizeof (xrdresp));
2826
2827 etext.clear();
2828 redirdest = "";
2829
2830 stringresp = "";
2831
2832 host = "";
2833 destination = "";
2834 hdr2cgistr = "";
2835 m_appended_hdr2cgistr = false;
2836 m_appended_asize = false;
2837
2838 iovP = 0;
2839 iovN = 0;
2840 iovL = 0;
2841
2842 if (opaque) delete(opaque);
2843 opaque = 0;
2844
2845 fopened = false;
2846 final = false;
2847 mScitag = -1;
2848
2849 m_repr_digest.clear();
2850 m_want_repr_digest.clear();
2851
2853 startTime = std::chrono::steady_clock::time_point::min();
2854}
@ kXR_noErrorYet
@ kXR_noResponsesYet
Definition XProtocol.hh:950
void reset()
resets this handler
std::string m_digest_header
The computed digest for the HTTP response header.
std::string stringresp
If we want to give a string as a response, we compose it here.
XrdHttpMonState monState

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

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

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

◆ setHttpStatusCode()

void XrdHttpReq::setHttpStatusCode ( int code)
inline

Definition at line 229 of file XrdHttpReq.hh.

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

◆ setTransferStatusHeader()

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

Definition at line 2081 of file XrdHttpReq.cc.

2081 {
2082 if (m_status_trailer) {
2083 if (header.empty()) {
2084 header += "Trailer: X-Transfer-Status";
2085 } else {
2086 header += "\r\nTrailer: X-Transfer-Status";
2087 }
2088 }
2089}

◆ userAgent()

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

Definition at line 265 of file XrdHttpReq.hh.

265{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 274 of file XrdHttpReq.hh.

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

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 293 of file XrdHttpReq.hh.

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

◆ depth

int XrdHttpReq::depth

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

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

◆ etagval

long long XrdHttpReq::etagval

Definition at line 349 of file XrdHttpReq.hh.

◆ etext

std::string XrdHttpReq::etext

Definition at line 339 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 354 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 353 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 351 of file XrdHttpReq.hh.

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

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 352 of file XrdHttpReq.hh.

Referenced by XrdHttpProtocol::doStat().

◆ filesize

long long XrdHttpReq::filesize

Definition at line 350 of file XrdHttpReq.hh.

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

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 346 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

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

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 345 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

Definition at line 295 of file XrdHttpReq.hh.

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

◆ length

ssize_t XrdHttpReq::length

◆ length_seen

bool XrdHttpReq::length_seen {false}

Definition at line 297 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ m_appended_asize

bool XrdHttpReq::m_appended_asize {false}

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

Definition at line 323 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

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

Referenced by reset().

◆ m_origin

std::string XrdHttpReq::m_origin

Definition at line 368 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ m_repr_digest

std::map<std::string,std::string> XrdHttpReq::m_repr_digest

Repr-Digest map where the key is the digest name and the value is the base64 encoded digest value.

Definition at line 373 of file XrdHttpReq.hh.

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

◆ m_req_cksum

XrdHttpChecksumHandler::XrdHttpChecksumRawPtr XrdHttpReq::m_req_cksum = nullptr

The checksum that was ran for this request.

Definition at line 310 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_resource_with_digest

XrdOucString XrdHttpReq::m_resource_with_digest

The checksum algorithm is specified as part of the opaque data in the URL. Hence, when a digest is generated to satisfy a request, we cache the tweaked URL in this data member.

Definition at line 315 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ m_want_digest

std::string XrdHttpReq::m_want_digest

The requested digest type.

Definition at line 307 of file XrdHttpReq.hh.

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

◆ m_want_repr_digest

std::map<std::string,uint8_t> XrdHttpReq::m_want_repr_digest

Want-Repr-Digest map where the key is the digest name and the value is the preference (between 0 and 9)

Definition at line 377 of file XrdHttpReq.hh.

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

◆ monState

XrdHttpMonState XrdHttpReq::monState

Definition at line 379 of file XrdHttpReq.hh.

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

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 366 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

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

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 340 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 361 of file XrdHttpReq.hh.

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

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 269 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 270 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

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

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 331 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

Definition at line 299 of file XrdHttpReq.hh.

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

◆ startTime

std::chrono::steady_clock::time_point XrdHttpReq::startTime = std::chrono::steady_clock::time_point::min()

Definition at line 370 of file XrdHttpReq.hh.

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

◆ stringresp

std::string XrdHttpReq::stringresp

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

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

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 338 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

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

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


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