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::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.
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
XrdOucEnvopaque
 The opaque data, after parsing.
std::vector< readahead_listralist
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 819 of file XrdHttpReq.cc.

819 {
820 if (hdr2cgistr.length() > 0) {
821 hdr2cgistr.append("&");
822 }
823 hdr2cgistr.append(key);
824 hdr2cgistr.append("=");
825 hdr2cgistr.append(value);
826}
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 711 of file XrdHttpReq.cc.

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

Referenced by 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
@ 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, kXR_error, kXR_isDirectory, kXR_open, request, 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) {
541 readRangeHandler.NotifyError();
542 return false;
543 }
544
545 if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
546 return false;
547
548
549 return true;
550};
virtual int Send(const struct iovec *headP, int headN, const struct iovec *tailP, int tailN)

References 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.

◆ 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.
178 readRangeHandler.ParseContentRange(val);
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)
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

References addCgi(), allheaders, depth, destination, keepalive, length, length_seen, m_origin, m_repr_digest, m_want_digest, m_want_repr_digest, MAX_TK_LEN, opaque, XrdHttpHeaderUtils::parseContentLength(), XrdHttpHeaderUtils::parseReprDigest(), XrdHttpHeaderUtils::parseTransferEncoding(), XrdHttpHeaderUtils::parseWantReprDigest(), readRangeHandler, request, rtMalformed, sendcontinue, and trim().

Here is the call 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 940 of file XrdHttpReq.cc.

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

References XrdOucString::append(), appendOpaque(), XrdOucString::c_str(), closeAfterError, XrdHttpProtocol::StaticPreloadInfo::data, DEBUG, depth, destination, encode_opaque(), encode_str(), XrdOucString::endswith(), XrdOucString::erasefromend(), fhandle, fileflags, filesize, fopened, hdr2cgistr, host, 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, m_appended_asize, m_appended_hdr2cgistr, m_req_cksum, m_resource_with_digest, m_want_digest, m_want_repr_digest, obfuscateAuth(), opaque, parseBody(), ProcessHTTPReq(), XrdHttpExtHandler::ProcessReq(), ralist, readClosing, readRangeHandler, ReqReadV(), reqstate, request, reset(), resource, resourceplusopaque, rtDELETE, rtGET, rtHEAD, rtMalformed, rtMKCOL, rtMOVE, rtOPTIONS, rtPATCH, rtPROPFIND, rtPUT, rtUnknown, rtUnset, sendcontinue, startTime, STR_NPOS, TRACE, TRACE_DEBUG, TRACEI, TRACING, writtenbytes, and xrdreq.

Referenced by 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.

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

602 {
603
604
605
606 char buf[512];
607 char hash[512];
608 hash[0] = '\0';
609
610 bool invalid_host = false;
611
612 if (!hname) {
613 invalid_host = true;
614 } else {
615 for (const char *c = hname; *c; ++c)
616 if (*c == '\r' || *c == '\n')
617 invalid_host = true;
618 }
619
620 if (invalid_host) {
621 prot->SendSimpleResp(502, nullptr, nullptr, "Invalid redirect host", 0, false);
622 return keepalive;
623 }
624
625 if (prot->isdesthttps)
626 redirdest = "Location: https://";
627 else
628 redirdest = "Location: http://";
629
630 // port < 0 signals switch to full URL
631 if (port < 0)
632 {
633 if (strncmp(hname, "file://", 7) == 0)
634 {
635 TRACE(REQ, " XrdHttpReq::Redir Switching to file:// ");
636 redirdest = "Location: "; // "file://" already contained in hname
637 }
638 }
639 // Beware, certain Ofs implementations (e.g. EOS) add opaque data directly to the host name
640 // This must be correctly treated here and appended to the opaque info
641 // that we may already have
642 char *pp = strchr((char *)hname, '?');
643 char *vardata = 0;
644 if (pp) {
645 *pp = '\0';
646 redirdest += hname;
647 vardata = pp+1;
648 int varlen = strlen(vardata);
649
650 //Now extract the remaining, vardata points to it
651 while(*vardata == '&' && varlen) {vardata++; varlen--;}
652
653 // Put the question mark back where it was
654 *pp = '?';
655 }
656 else
657 redirdest += hname;
658
659 if (port > 0) {
660 sprintf(buf, ":%d", port);
661 redirdest += buf;
662 }
663
664 redirdest += encode_str(resource.c_str()).c_str();
665
666 // Here we put back the opaque info, if any
667 if (vardata) {
668 redirdest += "?&";
669 redirdest += encode_opaque(vardata).c_str();
670 }
671
672 // Shall we put also the opaque data of the request? Maybe not
673 //int l;
674 //if (opaque && opaque->Env(l))
675 // redirdest += opaque->Env(l);
676
677
678 time_t timenow = 0;
679 if (!prot->isdesthttps && prot->ishttps) {
680 // If the destination is not https, then we suppose that it
681 // will need this token to fill its authorization info
682 timenow = time(0);
683 calcHashes(hash, this->resource.c_str(), (kXR_int16) request,
684 &prot->SecEntity,
685 timenow,
686 prot->secretkey);
687 }
688
689 if (hash[0]) {
690 appendOpaque(redirdest, &prot->SecEntity, hash, timenow);
691 } else
692 appendOpaque(redirdest, 0, 0, 0);
693
694 if (!prot->strp_cgi_params.empty()) {
695 stripCgi(redirdest, prot->strp_cgi_params); /* appendOpaque() may have added credentials */
696 }
697
698 TRACE(REQ, " XrdHttpReq::Redir Redirecting to " << redirdest.c_str());
699
700 if (request != rtGET)
701 prot->SendSimpleResp(307, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
702 else
703 prot->SendSimpleResp(302, NULL, (char *) redirdest.c_str(), 0, 0, keepalive);
704
705 bool ret_keepalive = keepalive; // reset() clears keepalive
706 reset();
707 return ret_keepalive;
708};
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)
void stripCgi(std::string &url, const std::unordered_set< std::string > &cgiKeys)
XrdOucString redirdest

References appendOpaque(), calcHashes(), encode_opaque(), encode_str(), 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
477 xrdreq.header.requestid = htons(kXR_readv);
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}
@ kXR_readv
Definition XProtocol.hh:138

References kXR_readv, ralist, 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 2771 of file XrdHttpReq.cc.

2771 {
2772
2773 TRACE(REQ, " XrdHttpReq request ended.");
2774
2775 //if (xmlbody) xmlFreeDoc(xmlbody);
2776 readRangeHandler.reset();
2777 readClosing = false;
2778 closeAfterError = false;
2779 writtenbytes = 0;
2780 etext.clear();
2781 redirdest = "";
2782
2783 // // Here we should deallocate this
2784 // const struct iovec *iovP //!< pointer to data array
2785 // int iovN, //!< array count
2786 // int iovL, //!< byte count
2787 // bool final //!< true -> final result
2788
2789
2790 //xmlbody = 0;
2791 depth = 0;
2794 ralist.clear();
2795 ralist.shrink_to_fit();
2796
2797 request = rtUnset;
2798 resource = "";
2799 allheaders.clear();
2800
2801 // Reset the state of the request's digest request.
2802 m_want_digest.clear();
2803 m_digest_header.clear();
2804 m_req_cksum = nullptr;
2805
2806 m_user_agent = "";
2807 m_origin = "";
2808
2809 httpStatusCode = -1;
2810 initialStatusCode= -1;
2811 httpErrorCode = "";
2812 httpErrorBody = "";
2813
2814 headerok = false;
2815 keepalive = true;
2816 length = 0;
2817 length_seen = false;
2818 filesize = 0;
2819 depth = 0;
2820 sendcontinue = false;
2821
2822 m_transfer_encoding_chunked = false;
2823 m_current_chunk_size = -1;
2824 m_current_chunk_offset = 0;
2825
2826 m_trailer_headers = false;
2827 m_status_trailer = false;
2828
2830 reqstate = 0;
2831
2832 memset(&xrdreq, 0, sizeof (xrdreq));
2833 memset(&xrdresp, 0, sizeof (xrdresp));
2835
2836 etext.clear();
2837 redirdest = "";
2838
2839 stringresp = "";
2840
2841 host = "";
2842 destination = "";
2843 hdr2cgistr = "";
2844 m_appended_hdr2cgistr = false;
2845 m_appended_asize = false;
2846
2847 iovP = 0;
2848 iovN = 0;
2849 iovL = 0;
2850
2851 if (opaque) delete(opaque);
2852 opaque = 0;
2853
2854 fopened = false;
2855 final = false;
2856 mScitag = -1;
2857
2858 m_repr_digest.clear();
2859 m_want_repr_digest.clear();
2860
2862 startTime = std::chrono::steady_clock::time_point::min();
2863}
@ kXR_noErrorYet
@ kXR_noResponsesYet
Definition XProtocol.hh:950
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, resource, rtUnset, sendcontinue, startTime, stringresp, TRACE, writtenbytes, xrderrcode, xrdreq, and xrdresp.

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

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

2090 {
2091 if (m_status_trailer) {
2092 if (header.empty()) {
2093 header += "Trailer: X-Transfer-Status";
2094 } else {
2095 header += "\r\nTrailer: X-Transfer-Status";
2096 }
2097 }
2098}

◆ userAgent()

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

Definition at line 265 of file XrdHttpReq.hh.

265{return m_user_agent;}

Member Data Documentation

◆ allheaders

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

Definition at line 274 of file XrdHttpReq.hh.

Referenced by parseLine(), 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 ProcessHTTPReq().

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 352 of file XrdHttpReq.hh.

◆ filesize

long long XrdHttpReq::filesize

Definition at line 350 of file XrdHttpReq.hh.

Referenced by 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(), 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.

297{false}; // Set once a Content-Length header has been accepted (RFC 7230 ยง3.3.3 rule 4).

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.

323{false};

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(), 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 ProcessHTTPReq(), and reset().

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 269 of file XrdHttpReq.hh.

Referenced by Error(), parseFirstLine(), parseLine(), 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(), 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 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 Error(), 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: