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
long long length
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 65 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 76 of file XrdHttpReq.hh.

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 207 of file XrdHttpReq.hh.

207 :
208 readRangeHandler(rcfg), closeAfterError(false), keepalive(true) {
209
210 prot = protinstance;
211 length = 0;
212 //xmlbody = 0;
213 depth = 0;
214 opaque = 0;
215 writtenbytes = 0;
216 fopened = false;
217 headerok = false;
218 mScitag = -1;
219 };
long long length
bool headerok
Tells if we have finished reading the header.
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 760 of file XrdHttpReq.cc.

760 {
761 if (hdr2cgistr.length() > 0) {
762 hdr2cgistr.append("&");
763 }
764 hdr2cgistr.append(key);
765 hdr2cgistr.append("=");
766 hdr2cgistr.append(value);
767}
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 652 of file XrdHttpReq.cc.

652 {
653
654 int l = 0;
655 char * p = 0;
656 if (opaque)
657 p = opaque->Env(l);
658
659 if (hdr2cgistr.empty() && (l < 2) && !hash) return;
660
661 // this works in most cases, except if the url already contains the xrdhttp tokens
662 s = s + "?";
663 if (!hdr2cgistr.empty()) {
664 s += encode_opaque(hdr2cgistr).c_str();
665 }
666 if (p && (l > 1)) {
667 if (!hdr2cgistr.empty()) {
668 s = s + "&";
669 }
670 s = s + encode_opaque(p + 1).c_str();
671 }
672
673 if (hash) {
674 if (l > 1) s += "&";
675 s += "xrdhttptk=";
676 s += hash;
677
678 s += "&xrdhttptime=";
679 char buf[256];
680 sprintf(buf, "%lld", (long long) tnow);
681 s += buf;
682
683 if (secent) {
684 if (secent->name) {
685 s += "&xrdhttpname=";
686 s += encode_str(secent->name).c_str();
687 }
688 }
689
690 if (secent->vorg) {
691 s += "&xrdhttpvorg=";
692 s += encode_str(secent->vorg).c_str();
693 }
694
695 if (secent->host) {
696 s += "&xrdhttphost=";
697 s += encode_str(secent->host).c_str();
698 }
699
700 if (secent->moninfo) {
701 s += "&xrdhttpdn=";
702 s += encode_str(secent->moninfo).c_str();
703 }
704
705 if (secent->role) {
706 s += "&xrdhttprole=";
707 s += encode_str(secent->role).c_str();
708 }
709
710 if (secent->grps) {
711 s += "&xrdhttpgrps=";
712 s += encode_str(secent->grps).c_str();
713 }
714
715 if (secent->endorsements) {
716 s += "&xrdhttpendorsements=";
717 s += encode_str(secent->endorsements).c_str();
718 }
719
720 if (secent->credslen) {
721 s += "&xrdhttpcredslen=";
722 char buf[16];
723 sprintf(buf, "%d", secent->credslen);
724 s += encode_str(buf).c_str();
725 }
726
727 if (secent->credslen) {
728 if (secent->creds) {
729 s += "&xrdhttpcreds=";
730 // Apparently this string might be not 0-terminated (!)
731 char *zerocreds = strndup(secent->creds, secent->credslen);
732 if (zerocreds) {
733 s += encode_str(zerocreds).c_str();
734 free(zerocreds);
735 }
736 }
737 }
738 }
739 }
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 444 of file XrdHttpReq.cc.

444 {
445 std::ostringstream s;
446
447 s << "\r\n--" << token << "\r\n";
448 s << "Content-type: text/plain; charset=UTF-8\r\n";
449 s << "Content-range: bytes " << bytestart << "-" << byteend << "/" << fsz << "\r\n\r\n";
450
451 return s.str();
452}

◆ buildPartialHdrEnd()

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

Build the closing part for a multipart response.

Definition at line 454 of file XrdHttpReq.cc.

454 {
455 std::ostringstream s;
456
457 s << "\r\n--" << token << "--\r\n";
458
459 return s.str();
460}

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

468 {
469
470 TRACE(REQ, " XrdHttpReq::Data! final=" << final);
471
472 this->xrdresp = kXR_ok;
473 this->iovP = iovP_;
474 this->iovN = iovN_;
475 this->iovL = iovL_;
476 this->final = final_;
477
478 if (PostProcessHTTPReq(final_)) reset();
479
480 return true;
481
482};
@ 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 508 of file XrdHttpReq.cc.

508 {
509
510 TRACE(REQ, " XrdHttpReq::Done");
511
512 xrdresp = kXR_ok;
513
514 this->iovN = 0;
515
516 int r = PostProcessHTTPReq(true);
517 // Beware, we don't have to reset() if the result is 0
518 if (r) reset();
519 if (r < 0) return false;
520
521
522 return true;
523};

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

528 {
529
530 TRACE(REQ, " XrdHttpReq::Error");
531
533 xrderrcode = (XErrorCode) ecode;
534
535 if (etext_) {
536 char *s = escapeXML(etext_);
537 this->etext = s;
538 free(s);
539 }
540
541 auto rc = PostProcessHTTPReq();
542 if (rc) {
543 reset();
544 }
545
546 // If we are servicing a GET on a directory, it'll generate an error for the default
547 // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
548 // generate a directory listing (if configured).
549 if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
550 return true;
551
552 return rc == 0;
553};
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 484 of file XrdHttpReq.cc.

486 {
487
488 // sendfile about to be sent by bridge for fetching data for GET:
489 // no https, no chunked+trailer, no multirange
490
491 //prot->SendSimpleResp(200, NULL, NULL, NULL, dlen);
492 int rc = info.Send(0, 0, 0, 0);
493 TRACE(REQ, " XrdHttpReq::File dlen:" << dlen << " send rc:" << rc);
494 bool start, finish;
495 // short read will be classed as error
496 if (rc) {
497 readRangeHandler.NotifyError();
498 return false;
499 }
500
501 if (readRangeHandler.NotifyReadResult(dlen, nullptr, start, finish) < 0)
502 return false;
503
504
505 return true;
506};
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 226 of file XrdHttpReq.hh.

226{ return httpStatusCode;}

◆ getInitialStatusCode()

int XrdHttpReq::getInitialStatusCode ( )
inline

Definition at line 225 of file XrdHttpReq.hh.

225{ 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 275 of file XrdHttpReq.cc.

275 {
276
277 char *key = line;
278
279 int pos;
280
281 // Do the naive parsing
282 if (!line) return -1;
283
284 // Look for the first space-delimited token
285 char *p = strchr((char *) line, (int) ' ');
286 if (!p) {
288 return -1;
289 }
290
291
292 pos = p - line;
293 // The first token cannot be too long
294 if (pos > MAX_TK_LEN - 1) {
296 return -2;
297 }
298
299 // The first space-delimited char cannot be the first one
300 // this allows to deal with the case when a client sends a first line that starts with a space " GET / HTTP/1.1"
301 if(pos == 0) {
303 return -4;
304 }
305
306 // the first token must be non empty
307 if (pos > 0) {
308 line[pos] = 0;
309 char *val = line + pos + 1;
310
311 // Here we are supposed to initialize whatever flag or variable that is needed
312 // by looking at the first token of the line
313
314 // The token is key
315 // The remainder is val, look for the resource
316 p = strchr((char *) val, (int) ' ');
317
318 if (!p) {
320 line[pos] = ' ';
321 return -3;
322 }
323
324 *p = '\0';
325 parseResource(val);
326
327 *p = ' ';
328
329 // Xlate the known header lines
330 if (!strcmp(key, "GET")) {
331 request = rtGET;
332 } else if (!strcmp(key, "HEAD")) {
333 request = rtHEAD;
334 } else if (!strcmp(key, "PUT")) {
335 request = rtPUT;
336 } else if (!strcmp(key, "POST")) {
337 request = rtPOST;
338 } else if (!strcmp(key, "PATCH")) {
340 } else if (!strcmp(key, "OPTIONS")) {
342 } else if (!strcmp(key, "DELETE")) {
344 } else if (!strcmp(key, "PROPFIND")) {
346 } else if (!strcmp(key, "MKCOL")) {
348 } else if (!strcmp(key, "MOVE")) {
349 request = rtMOVE;
350 } else if (!strcmp(key, "COPY")) {
351 request = rtCOPY;
352 } else {
354 }
355
356 requestverb = key;
357
358 // The last token should be the protocol. If it is HTTP/1.0, then
359 // keepalive is disabled by default.
360 if (!strcmp(p+1, "HTTP/1.0\r\n")) {
361 keepalive = false;
362 }
363 line[pos] = ' ';
364 }
365
366 return 0;
367}
#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 length = atoll(val);
181
182 } else if (!strcasecmp(key, "destination")) {
183 destination.assign(val, line+len-val);
185 } else if (!strcasecmp(key, "want-digest")) {
186 // Discard Want-Repr-Digest in favor of Want-Digest
187 m_want_repr_digest.clear();
188 m_want_digest.assign(val, line + len - val);
190 //Transform the user requests' want-digest to lowercase
191 std::transform(m_want_digest.begin(), m_want_digest.end(), m_want_digest.begin(), ::tolower);
192 } else if (!strcasecmp(key, "depth")) {
193 depth = -1;
194 if (strcmp(val, "infinity"))
195 depth = atoll(val);
196
197 } else if (!strcasecmp(key, "expect") && strstr(val, "100-continue")) {
198 sendcontinue = true;
199 } else if (!strcasecmp(key, "te") && strstr(val, "trailers")) {
200 m_trailer_headers = true;
201 } else if (!strcasecmp(key, "transfer-encoding") && strstr(val, "chunked")) {
202 m_transfer_encoding_chunked = true;
203 } else if (!strcasecmp(key, "x-transfer-status") && strstr(val, "true")) {
204 m_transfer_encoding_chunked = true;
205 m_status_trailer = true;
206 } else if (!strcasecmp(key, "scitag")) {
207 if(prot->pmarkHandle != nullptr) {
208 parseScitag(val);
209 }
210 } else if (!strcasecmp(key, "user-agent")) {
211 m_user_agent = val;
212 trim(m_user_agent);
213 } else if (!strcasecmp(key,"origin")) {
214 m_origin = val;
215 trim(m_origin);
216 } else if (!strcasecmp(key,"repr-digest")) {
218 } else if (!strcasecmp(key,"want-repr-digest")) {
219 if(m_want_digest.empty()) {
220 // If Want-Digest was set, don't parse want-repr-digest
222 }
223 } else {
224 // Some headers need to be translated into "local" cgi info.
225 auto it = std::find_if(prot->hdr2cgimap.begin(), prot->hdr2cgimap.end(),[key](const auto & item) {
226 return !strcasecmp(key,item.first.c_str());
227 });
228 if (it != prot->hdr2cgimap.end() && (opaque ? (0 == opaque->Get(it->second.c_str())) : true)) {
229 std::string s;
230 s.assign(val, line+len-val);
231 trim(s);
232 addCgi(it->second,s);
233 }
234 }
235
236
237 line[pos] = ':';
238 }
239
240 return 0;
241}
void trim(std::string &str)
Definition XrdHttpReq.cc:78
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)
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.
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, m_origin, m_repr_digest, m_want_digest, m_want_repr_digest, MAX_TK_LEN, opaque, XrdHttpHeaderUtils::parseReprDigest(), 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 881 of file XrdHttpReq.cc.

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

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

407 {
408
409
410 // Now we build the protocol-ready read ahead list
411 // and also put the correct placeholders inside the cache
412 int n = cl.size();
413 ralist.clear();
414 ralist.reserve(n);
415
416 int j = 0;
417 for (const auto &c: cl) {
418 ralist.emplace_back();
419 auto &ra = ralist.back();
420 memcpy(&ra.fhandle, this->fhandle, 4);
421
422 ra.offset = c.offset;
423 ra.rlen = c.size;
424 j++;
425 }
426
427 if (j > 0) {
428
429 // Prepare a request header
430
431 memset(&xrdreq, 0, sizeof (xrdreq));
432
433 xrdreq.header.requestid = htons(kXR_readv);
434 xrdreq.readv.dlen = htonl(j * sizeof (struct readahead_list));
435
436 clientMarshallReadAheadList(j);
437
438
439 }
440
441 return (j * sizeof (struct readahead_list));
442}
@ 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 2711 of file XrdHttpReq.cc.

2711 {
2712
2713 TRACE(REQ, " XrdHttpReq request ended.");
2714
2715 //if (xmlbody) xmlFreeDoc(xmlbody);
2716 readRangeHandler.reset();
2717 readClosing = false;
2718 closeAfterError = false;
2719 writtenbytes = 0;
2720 etext.clear();
2721 redirdest = "";
2722
2723 // // Here we should deallocate this
2724 // const struct iovec *iovP //!< pointer to data array
2725 // int iovN, //!< array count
2726 // int iovL, //!< byte count
2727 // bool final //!< true -> final result
2728
2729
2730 //xmlbody = 0;
2731 depth = 0;
2734 ralist.clear();
2735 ralist.shrink_to_fit();
2736
2737 request = rtUnset;
2738 resource = "";
2739 allheaders.clear();
2740
2741 // Reset the state of the request's digest request.
2742 m_want_digest.clear();
2743 m_digest_header.clear();
2744 m_req_cksum = nullptr;
2745
2746 m_user_agent = "";
2747 m_origin = "";
2748
2749 httpStatusCode = -1;
2750 initialStatusCode= -1;
2751 httpErrorCode = "";
2752 httpErrorBody = "";
2753
2754 headerok = false;
2755 keepalive = true;
2756 length = 0;
2757 filesize = 0;
2758 depth = 0;
2759 sendcontinue = false;
2760
2761 m_transfer_encoding_chunked = false;
2762 m_current_chunk_size = -1;
2763 m_current_chunk_offset = 0;
2764
2765 m_trailer_headers = false;
2766 m_status_trailer = false;
2767
2769 reqstate = 0;
2770
2771 memset(&xrdreq, 0, sizeof (xrdreq));
2772 memset(&xrdresp, 0, sizeof (xrdresp));
2774
2775 etext.clear();
2776 redirdest = "";
2777
2778 stringresp = "";
2779
2780 host = "";
2781 destination = "";
2782 hdr2cgistr = "";
2783 m_appended_hdr2cgistr = false;
2784 m_appended_asize = false;
2785
2786 iovP = 0;
2787 iovN = 0;
2788 iovL = 0;
2789
2790 if (opaque) delete(opaque);
2791 opaque = 0;
2792
2793 fopened = false;
2794 final = false;
2795 mScitag = -1;
2796
2797 m_repr_digest.clear();
2798 m_want_repr_digest.clear();
2799
2801 startTime = std::chrono::steady_clock::time_point::min();
2802}
@ 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, 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 228 of file XrdHttpReq.hh.

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

◆ setTransferStatusHeader()

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

Definition at line 2031 of file XrdHttpReq.cc.

2031 {
2032 if (m_status_trailer) {
2033 if (header.empty()) {
2034 header += "Trailer: X-Transfer-Status";
2035 } else {
2036 header += "\r\nTrailer: X-Transfer-Status";
2037 }
2038 }
2039}

◆ userAgent()

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

Definition at line 264 of file XrdHttpReq.hh.

264{return m_user_agent;}

Member Data Documentation

◆ allheaders

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

Definition at line 273 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 292 of file XrdHttpReq.hh.

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

◆ depth

int XrdHttpReq::depth

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

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

◆ etagval

long long XrdHttpReq::etagval

Definition at line 347 of file XrdHttpReq.hh.

◆ etext

std::string XrdHttpReq::etext

Definition at line 337 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 352 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 351 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 349 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 350 of file XrdHttpReq.hh.

◆ filesize

long long XrdHttpReq::filesize

Definition at line 348 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 344 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

Definition at line 353 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 318 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 284 of file XrdHttpReq.hh.

Referenced by XrdHttpReq(), and reset().

◆ host

std::string XrdHttpReq::host

The host field specified in the req.

Definition at line 300 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 343 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

Definition at line 294 of file XrdHttpReq.hh.

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

◆ length

long long XrdHttpReq::length

◆ m_appended_asize

bool XrdHttpReq::m_appended_asize {false}

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

Definition at line 321 of file XrdHttpReq.hh.

321{false};

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

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

Referenced by reset().

◆ m_origin

std::string XrdHttpReq::m_origin

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

Referenced by ProcessHTTPReq().

◆ m_want_digest

std::string XrdHttpReq::m_want_digest

The requested digest type.

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

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

◆ monState

XrdHttpMonState XrdHttpReq::monState

Definition at line 377 of file XrdHttpReq.hh.

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

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 364 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

Definition at line 278 of file XrdHttpReq.hh.

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

◆ ralist

std::vector<readahead_list> XrdHttpReq::ralist

Definition at line 246 of file XrdHttpReq.hh.

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 338 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 359 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 268 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 269 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

Definition at line 276 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 280 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 329 of file XrdHttpReq.hh.

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 329 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

Definition at line 297 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 368 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 356 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 362 of file XrdHttpReq.hh.

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 336 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

Definition at line 332 of file XrdHttpReq.hh.

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

◆ xrdresp

XResponseType XrdHttpReq::xrdresp

The last response data we got.

Definition at line 335 of file XrdHttpReq.hh.

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


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