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
}
 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 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 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.
 
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
 
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum = nullptr
 The checksum that was ran for this request.
 
std::string m_req_digest
 The requested digest type.
 
XrdOucString m_resource_with_digest
 
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::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 71 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 

Definition at line 81 of file XrdHttpReq.hh.

Constructor & Destructor Documentation

◆ XrdHttpReq()

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

Definition at line 212 of file XrdHttpReq.hh.

212 :
213 readRangeHandler(rcfg), closeAfterError(false), keepalive(true) {
214
215 prot = protinstance;
216 length = 0;
217 //xmlbody = 0;
218 depth = 0;
219 opaque = 0;
220 writtenbytes = 0;
221 fopened = false;
222 headerok = false;
223 mScitag = -1;
224 };
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 111 of file XrdHttpReq.cc.

111 {
112 //if (xmlbody) xmlFreeDoc(xmlbody);
113
114 reset();
115}
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 747 of file XrdHttpReq.cc.

747 {
748 if (hdr2cgistr.length() > 0) {
749 hdr2cgistr.append("&");
750 }
751 hdr2cgistr.append(key);
752 hdr2cgistr.append("=");
753 hdr2cgistr.append(value);
754}
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 639 of file XrdHttpReq.cc.

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

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

◆ buildPartialHdrEnd()

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

Build the closing part 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
449 return s.str();
450}

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

458 {
459
460 TRACE(REQ, " XrdHttpReq::Data! final=" << final);
461
462 this->xrdresp = kXR_ok;
463 this->iovP = iovP_;
464 this->iovN = iovN_;
465 this->iovL = iovL_;
466 this->final = final_;
467
468 if (PostProcessHTTPReq(final_)) reset();
469
470 return true;
471
472};
@ kXR_ok
Definition XProtocol.hh:899
#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 498 of file XrdHttpReq.cc.

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

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

518 {
519
520 TRACE(REQ, " XrdHttpReq::Error");
521
523 xrderrcode = (XErrorCode) ecode;
524
525 if (etext_) {
526 char *s = escapeXML(etext_);
527 this->etext = s;
528 free(s);
529 }
530
531 auto rc = PostProcessHTTPReq();
532 if (rc) {
533 reset();
534 }
535
536 // If we are servicing a GET on a directory, it'll generate an error for the default
537 // OSS (we don't assume this is always true). Catch and suppress the error so we can instead
538 // generate a directory listing (if configured).
539 if ((request == rtGET) && (xrdreq.header.requestid == ntohs(kXR_open)) && (xrderrcode == kXR_isDirectory))
540 return true;
541
542 return rc == 0;
543};
XErrorCode
Definition XProtocol.hh:989
@ kXR_isDirectory
@ kXR_error
Definition XProtocol.hh:903
@ kXR_open
Definition XProtocol.hh:122
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 474 of file XrdHttpReq.cc.

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

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

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

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

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

References keepalive, MAX_TK_LEN, request, requestverb, 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 117 of file XrdHttpReq.cc.

117 {
118
119 char *key = line;
120 int pos;
121
122 // Do the parsing
123 if (!line) return -1;
124
125
126 char *p = strchr((char *) line, (int) ':');
127 if (!p) {
128
130 return -1;
131 }
132
133 pos = (p - line);
134 if (pos > (MAX_TK_LEN - 1)) {
135
137 return -2;
138 }
139
140 if (pos > 0) {
141 line[pos] = 0;
142 char *val = line + pos + 1;
143
144 // Trim left
145 while ( (!isgraph(*val) || (!*val)) && (val < line+len)) val++;
146
147 // We memorize the headers also as a string
148 // because external plugins may need to process it differently
149 std::string ss = val;
150 if(ss.length() >= 2 && ss.substr(ss.length() - 2, 2) != "\r\n") {
152 return -3;
153 }
154 trim(ss);
155 allheaders[key] = ss;
156
157 // Here we are supposed to initialize whatever flag or variable that is needed
158 // by looking at the first token of the line
159 // The token is key
160 // The value is val
161
162 // Screen out the needed header lines
163 if (!strcasecmp(key, "connection")) {
164
165 if (!strcasecmp(val, "Keep-Alive\r\n")) {
166 keepalive = true;
167 } else if (!strcasecmp(val, "close\r\n")) {
168 keepalive = false;
169 }
170
171 } else if (!strcasecmp(key, "host")) {
172 parseHost(val);
173 } else if (!strcasecmp(key, "range")) {
174 // (rfc2616 14.35.1) says if Range header contains any range
175 // which is syntactically invalid the Range header should be ignored.
176 // Therefore no need for the range handler to report an error.
177 readRangeHandler.ParseContentRange(val);
178 } else if (!strcasecmp(key, "content-length")) {
179 length = atoll(val);
180
181 } else if (!strcasecmp(key, "destination")) {
182 destination.assign(val, line+len-val);
184 } else if (!strcasecmp(key, "want-digest")) {
185 m_req_digest.assign(val, line + len - val);
187 //Transform the user requests' want-digest to lowercase
188 std::transform(m_req_digest.begin(),m_req_digest.end(),m_req_digest.begin(),::tolower);
189 } else if (!strcasecmp(key, "depth")) {
190 depth = -1;
191 if (strcmp(val, "infinity"))
192 depth = atoll(val);
193
194 } else if (!strcasecmp(key, "expect") && strstr(val, "100-continue")) {
195 sendcontinue = true;
196 } else if (!strcasecmp(key, "te") && strstr(val, "trailers")) {
197 m_trailer_headers = true;
198 } else if (!strcasecmp(key, "transfer-encoding") && strstr(val, "chunked")) {
199 m_transfer_encoding_chunked = true;
200 } else if (!strcasecmp(key, "x-transfer-status") && strstr(val, "true")) {
201 m_transfer_encoding_chunked = true;
202 m_status_trailer = true;
203 } else if (!strcasecmp(key, "scitag")) {
204 if(prot->pmarkHandle != nullptr) {
205 parseScitag(val);
206 }
207 } else if (!strcasecmp(key, "user-agent")) {
208 m_user_agent = val;
209 trim(m_user_agent);
210 } else if (!strcasecmp(key,"origin")) {
211 m_origin = val;
212 trim(m_origin);
213 } else {
214 // Some headers need to be translated into "local" cgi info.
215 auto it = std::find_if(prot->hdr2cgimap.begin(), prot->hdr2cgimap.end(),[key](const auto & item) {
216 return !strcasecmp(key,item.first.c_str());
217 });
218 if (it != prot->hdr2cgimap.end() && (opaque ? (0 == opaque->Get(it->second.c_str())) : true)) {
219 std::string s;
220 s.assign(val, line+len-val);
221 trim(s);
222 addCgi(it->second,s);
223 }
224 }
225
226
227 line[pos] = ':';
228 }
229
230 return 0;
231}
void trim(std::string &str)
Definition XrdHttpReq.cc:77
std::string destination
The destination field specified in the req.
std::string m_req_digest
The requested digest type.
std::string m_origin
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_req_digest, MAX_TK_LEN, opaque, 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
944 // State variable for tracking the query parameter search
945 // - 0: Indicates we've not yet searched the URL for '?'
946 // - 1: Indicates we have a '?' and hence query parameters
947 // - 2: Indicates we do *not* have '?' present -- no query parameters
948 int query_param_status = 0;
949 if (!m_appended_asize) {
950 m_appended_asize = true;
951 if (request == rtPUT && length) {
952 if (query_param_status == 0) {
953 query_param_status = strchr(resourceplusopaque.c_str(), '?') ? 1 : 2;
954 }
955 resourceplusopaque.append((query_param_status == 1) ? '&' : '?');
956 query_param_status = 1;
957 auto length_str = std::to_string(length);
958 resourceplusopaque.append("oss.asize=");
959 resourceplusopaque.append(length_str.c_str());
960 if (!opaque) {
961 opaque = new XrdOucEnv();
962 }
963 opaque->Put("oss.asize", length_str.c_str());
964 }
965 }
966
968 if (!m_appended_hdr2cgistr && !hdr2cgistr.empty()) {
969 if (query_param_status == 0) {
970 query_param_status = strchr(resourceplusopaque.c_str(), '?') ? 1 : 2;
971 }
972 resourceplusopaque.append((query_param_status == 1) ? '&' : '?');
973
974 std::string hdr2cgistrEncoded = encode_opaque(hdr2cgistr);
975 resourceplusopaque.append(hdr2cgistrEncoded.c_str());
976 if (TRACING(TRACE_DEBUG)) {
977 // The obfuscation of "authz" will only be done if the server http.header2cgi config contains something that maps a header to this "authz" cgi.
978 // Unfortunately the obfuscation code will be called no matter what is configured in http.header2cgi.
979 std::string header2cgistrObf = obfuscateAuth(hdr2cgistr);
980
981 TRACEI(DEBUG, "Appended header fields to opaque info: '"
982 << header2cgistrObf.c_str() << "'");
983
984 }
985
987 }
988
989 // Verify if we have an external handler for this request
990 if (reqstate == 0) {
991 XrdHttpExtHandler *exthandler = prot->FindMatchingExtHandler(*this);
992 if (exthandler) {
993 XrdHttpExtReq xreq(this, prot);
994 int r = exthandler->ProcessReq(xreq);
995 reset();
996 if (!r) return 1; // All went fine, response sent
997 if (r < 0) return -1; // There was a hard error... close the connection
998
999 return 1; // There was an error and a response was sent
1000 }
1001 }
1002
1003 //
1004 // Here we process the request locally
1005 //
1006
1007 switch (request) {
1010 {
1011 prot->SendSimpleResp(400, NULL, NULL, (char *) "Request unknown", 0, false);
1012 reset();
1013 return -1;
1014 }
1016 {
1017 prot->SendSimpleResp(400, NULL, NULL, (char *) "Request malformed", 0, false);
1018 reset();
1019 return -1;
1020 }
1021 case XrdHttpReq::rtHEAD:
1022 {
1023 if (reqstate == 0) {
1024 // Always start with Stat; in the case of a checksum request, we'll have a follow-up query
1025 if (prot->doStat((char *) resourceplusopaque.c_str())) {
1026 prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
1027 return -1;
1028 }
1029 return 0;
1030 } else {
1031 const char *opaque = strchr(resourceplusopaque.c_str(), '?');
1032 // Note that doChksum requires that the memory stays alive until the callback is invoked.
1034
1035 m_req_cksum = prot->cksumHandler.getChecksumToRun(m_req_digest);
1036 if(!m_req_cksum) {
1037 // No HTTP IANA checksums have been configured by the server admin, return a "METHOD_NOT_ALLOWED" error
1038 prot->SendSimpleResp(403, NULL, NULL, (char *) "No HTTP-IANA compatible checksums have been configured.", 0, false);
1039 return -1;
1040 }
1041 if (!opaque) {
1042 m_resource_with_digest += "?cks.type=";
1043 m_resource_with_digest += m_req_cksum->getXRootDConfigDigestName().c_str();
1044 } else {
1045 m_resource_with_digest += "&cks.type=";
1046 m_resource_with_digest += m_req_cksum->getXRootDConfigDigestName().c_str();
1047 }
1048 if (prot->doChksum(m_resource_with_digest) < 0) {
1049 // In this case, the Want-Digest header was set and PostProcess gave the go-ahead to do a checksum.
1050 prot->SendSimpleResp(500, NULL, NULL, (char *) "Failed to create initial checksum request.", 0, false);
1051 return -1;
1052 }
1053 return 1;
1054 }
1055 }
1056 case XrdHttpReq::rtGET:
1057 {
1058 int retval = keepalive ? 1 : -1; // reset() clears keepalive
1059
1060 if (resource.beginswith("/static/")) {
1061
1062 // This is a request for a /static resource
1063 // If we have to use the embedded ones then we return the ones in memory as constants
1064
1065 // The sysadmin can always redirect the request to another host that
1066 // contains his static resources
1067
1068 // We also allow xrootd to preread from the local disk all the files
1069 // that have to be served as static resources.
1070
1071 if (prot->embeddedstatic) {
1072
1073 // Default case: the icon and the css of the HTML rendering of XrdHttp
1074 if (resource == "/static/css/xrdhttp.css") {
1075 prot->SendSimpleResp(200, NULL, NULL, (char *) static_css_xrdhttp_css, static_css_xrdhttp_css_len, keepalive);
1076 reset();
1077 return retval;
1078 }
1079 if (resource == "/static/icons/xrdhttp.ico") {
1080 prot->SendSimpleResp(200, NULL, NULL, (char *) favicon_ico, favicon_ico_len, keepalive);
1081 reset();
1082 return retval;
1083 }
1084
1085 }
1086
1087 // If we are here then none of the embedded resources match (or they are disabled)
1088 // We may have to redirect to a host that is supposed to serve the static resources
1089 if (prot->staticredir) {
1090
1091 XrdOucString s = "Location: ";
1092 s.append(prot->staticredir);
1093
1094 if (s.endswith('/'))
1095 s.erasefromend(1);
1096
1097 s.append(resource);
1098 appendOpaque(s, 0, 0, 0);
1099
1100 prot->SendSimpleResp(302, NULL, (char *) s.c_str(), 0, 0, false);
1101 return -1;
1102
1103
1104 } else {
1105
1106 // We lookup the requested path in a hash containing the preread files
1107 if (prot->staticpreload) {
1108 XrdHttpProtocol::StaticPreloadInfo *mydata = prot->staticpreload->Find(resource.c_str());
1109 if (mydata) {
1110 prot->SendSimpleResp(200, NULL, NULL, (char *) mydata->data, mydata->len, keepalive);
1111 reset();
1112 return retval;
1113 }
1114 }
1115
1116 }
1117
1118
1119 }
1120
1121 // The reqstate parameter basically moves us through a simple state machine.
1122 // To optimize things, we start off by opening the file; if it turns out to be a directory, then
1123 // we close the file handle and switch to doing a HTML-based rendering of the directory. This
1124 // avoids needing to always to do "stat" first to determine the next step (since the file-open also
1125 // does a "stat").
1126 // - 0: Perform an open on the resource
1127 // - 1: Perform a checksum request on the resource (only if requested in header; otherwise skipped)
1128 // - 2: Perform a close (for dirlist only)
1129 // - 3: Perform a dirlist.
1130 // - 4+: Reads from file; if at end, perform a close.
1131 switch (reqstate) {
1132 case 0: // Open the path for reading.
1133 {
1134 memset(&xrdreq, 0, sizeof (ClientRequest));
1135 xrdreq.open.requestid = htons(kXR_open);
1136 l = resourceplusopaque.length() + 1;
1137 xrdreq.open.dlen = htonl(l);
1138 xrdreq.open.mode = 0;
1139 xrdreq.open.options = htons(kXR_retstat | kXR_open_read | ((readRangeHandler.getMaxRanges() <= 1) ? kXR_seqio : 0));
1140
1141 if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1142 prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, false);
1143 return -1;
1144 }
1145
1146 // Prepare to chunk up the request
1147 writtenbytes = 0;
1148
1149 // We want to be invoked again after this request is finished
1150 return 0;
1151 }
1152 case 1: // Checksum request
1153 if (!(fileflags & kXR_isDir) && !m_req_digest.empty()) {
1154 // In this case, the Want-Digest header was set.
1155 bool has_opaque = strchr(resourceplusopaque.c_str(), '?');
1156 // Note that doChksum requires that the memory stays alive until the callback is invoked.
1157 m_req_cksum = prot->cksumHandler.getChecksumToRun(m_req_digest);
1158 if(!m_req_cksum) {
1159 // No HTTP IANA checksums have been configured by the server admin, return a "METHOD_NOT_ALLOWED" error
1160 prot->SendSimpleResp(403, NULL, NULL, (char *) "No HTTP-IANA compatible checksums have been configured.", 0, false);
1161 return -1;
1162 }
1164 if (has_opaque) {
1165 m_resource_with_digest += "&cks.type=";
1166 m_resource_with_digest += m_req_cksum->getXRootDConfigDigestName().c_str();
1167 } else {
1168 m_resource_with_digest += "?cks.type=";
1169 m_resource_with_digest += m_req_cksum->getXRootDConfigDigestName().c_str();
1170 }
1171 if (prot->doChksum(m_resource_with_digest) < 0) {
1172 prot->SendSimpleResp(500, NULL, NULL, (char *) "Failed to start internal checksum request to satisfy Want-Digest header.", 0, false);
1173 return -1;
1174 }
1175 return 0;
1176 } else {
1177 TRACEI(DEBUG, "No checksum requested; skipping to request state 2");
1178 reqstate += 1;
1179 }
1180 // fallthrough
1181 case 2: // Close file handle for directory
1182 if ((fileflags & kXR_isDir) && fopened) {
1183 memset(&xrdreq, 0, sizeof (ClientRequest));
1184 xrdreq.close.requestid = htons(kXR_close);
1185 memcpy(xrdreq.close.fhandle, fhandle, 4);
1186
1187 if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1188 mapXrdErrorToHttpStatus();
1189 return sendFooterError("Could not run close request on the bridge");
1190 }
1191 return 0;
1192 } else {
1193 reqstate += 1;
1194 }
1195 // fallthrough
1196 case 3: // List directory
1197 if (fileflags & kXR_isDir) {
1198 if (prot->listdeny) {
1199 prot->SendSimpleResp(503, NULL, NULL, (char *) "Listings are disabled.", 0, false);
1200 return -1;
1201 }
1202
1203 if (prot->listredir) {
1204 XrdOucString s = "Location: ";
1205 s.append(prot->listredir);
1206
1207 if (s.endswith('/'))
1208 s.erasefromend(1);
1209
1210 s.append(resource);
1211 appendOpaque(s, 0, 0, 0);
1212
1213 prot->SendSimpleResp(302, NULL, (char *) s.c_str(), 0, 0, false);
1214 return -1;
1215 }
1216
1217 std::string res;
1218 res = resourceplusopaque.c_str();
1219
1220 // --------- DIRLIST
1221 memset(&xrdreq, 0, sizeof (ClientRequest));
1222 xrdreq.dirlist.requestid = htons(kXR_dirlist);
1223 xrdreq.dirlist.options[0] = kXR_dstat;
1224 l = res.length() + 1;
1225 xrdreq.dirlist.dlen = htonl(l);
1226
1227 if (!prot->Bridge->Run((char *) &xrdreq, (char *) res.c_str(), l)) {
1228 mapXrdErrorToHttpStatus();
1229 prot->SendSimpleResp(httpStatusCode, NULL, NULL, httpErrorBody.c_str(), httpErrorBody.length(), false);
1230 sendFooterError("Could not run listing request on the bridge");
1231 return -1;
1232 }
1233
1234 // We don't want to be invoked again after this request is finished
1235 return 1;
1236 }
1237 else {
1238 reqstate += 1;
1239 }
1240 // fallthrough
1241 case 4:
1242 {
1243 auto retval = ReturnGetHeaders();
1244 if (retval) {
1245 return retval;
1246 }
1247 }
1248 // fallthrough
1249 default: // Read() or Close(); reqstate is 4+
1250 {
1251 const XrdHttpIOList &readChunkList = readRangeHandler.NextReadList();
1252
1253 // Close() if we have finished, otherwise read the next chunk
1254
1255 // --------- CLOSE
1256 if ( closeAfterError || readChunkList.empty() )
1257 {
1258
1259 memset(&xrdreq, 0, sizeof (ClientRequest));
1260 xrdreq.close.requestid = htons(kXR_close);
1261 memcpy(xrdreq.close.fhandle, fhandle, 4);
1262
1263 if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1264 TRACEI(REQ, " Failed to run close request on the bridge.");
1265 // Note: we have already completed the request and sent the data to the client.
1266 // Hence, there's no need to send an error. However, since the bridge is potentially
1267 // in a bad state, we close the TCP socket to force the client to reconnect.
1268 return -1;
1269 }
1270
1271 // We have finished
1272 readClosing = true;
1273 return 1;
1274
1275 }
1276 // --------- READ or READV
1277
1278 if ( readChunkList.size() == 1 ) {
1279 // Use a read request for single range
1280
1281 long l;
1282 long long offs;
1283
1284 // --------- READ
1285 memset(&xrdreq, 0, sizeof (xrdreq));
1286 xrdreq.read.requestid = htons(kXR_read);
1287 memcpy(xrdreq.read.fhandle, fhandle, 4);
1288 xrdreq.read.dlen = 0;
1289
1290 offs = readChunkList[0].offset;
1291 l = readChunkList[0].size;
1292
1293 xrdreq.read.offset = htonll(offs);
1294 xrdreq.read.rlen = htonl(l);
1295
1296 // If we are using HTTPS or if the client requested trailers, or if the
1297 // read concerns a multirange reponse, disable sendfile
1298 // (in the latter two cases, the extra framing is only done in PostProcessHTTPReq)
1299 if (prot->ishttps || (m_transfer_encoding_chunked && m_trailer_headers) ||
1300 !readRangeHandler.isSingleRange()) {
1301 if (!prot->Bridge->setSF((kXR_char *) fhandle, false)) {
1302 TRACE(REQ, " XrdBridge::SetSF(false) failed.");
1303
1304 }
1305 }
1306
1307
1308
1309 if (l <= 0) {
1310 if (l < 0) {
1311 TRACE(ALL, " Data sizes mismatch.");
1312 return -1;
1313 }
1314 else {
1315 TRACE(ALL, " No more bytes to send.");
1316 reset();
1317 return 1;
1318 }
1319 }
1320
1321 if ((offs >= filesize) || (offs+l > filesize)) {
1322 httpStatusCode = 416;
1323 httpErrorBody = "Range Not Satisfiable";
1324 std::stringstream ss;
1325 ss << "Requested range " << l << "@" << offs << " is past the end of file (" << filesize << ")";
1326 return sendFooterError(ss.str());
1327 }
1328
1329 if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1330 mapXrdErrorToHttpStatus();
1331 return sendFooterError("Could not run read request on the bridge");
1332 }
1333 } else {
1334 // --------- READV
1335
1336 length = ReqReadV(readChunkList);
1337
1338 if (!prot->Bridge->Run((char *) &xrdreq, (char *) &ralist[0], length)) {
1339 mapXrdErrorToHttpStatus();
1340 return sendFooterError("Could not run ReadV request on the bridge");
1341 }
1342
1343 }
1344
1345 // We want to be invoked again after this request is finished
1346 return 0;
1347 } // case 3+
1348
1349 } // switch (reqstate)
1350
1351
1352 } // case XrdHttpReq::rtGET
1353
1354 case XrdHttpReq::rtPUT:
1355 {
1356 //if (prot->ishttps) {
1357 //prot->SendSimpleResp(501, NULL, NULL, (char *) "HTTPS not supported yet for direct writing. Sorry.", 0);
1358 //return -1;
1359 //}
1360
1361 if (!fopened) {
1362
1363 // --------- OPEN for write!
1364 memset(&xrdreq, 0, sizeof (ClientRequest));
1365 xrdreq.open.requestid = htons(kXR_open);
1366 l = resourceplusopaque.length() + 1;
1367 xrdreq.open.dlen = htonl(l);
1368 xrdreq.open.mode = htons(kXR_ur | kXR_uw | kXR_gw | kXR_gr | kXR_or);
1369 if (! XrdHttpProtocol::usingEC)
1370 xrdreq.open.options = htons(kXR_mkpath | kXR_open_wrto | kXR_delete);
1371 else
1372 xrdreq.open.options = htons(kXR_mkpath | kXR_open_wrto | kXR_new);
1373
1374 if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1375 prot->SendSimpleResp(404, NULL, NULL, (char *) "Could not run request.", 0, keepalive);
1376 return -1;
1377 }
1378
1379
1380 // We want to be invoked again after this request is finished
1381 // Only if there is data to fetch from the socket or there will
1382 // never be more data
1383 if (prot->BuffUsed() > 0 || (length == 0 && !sendcontinue))
1384 return 0;
1385
1386 return 1;
1387
1388 } else {
1389
1390 if (m_transfer_encoding_chunked) {
1391 if (m_current_chunk_size == m_current_chunk_offset) {
1392 // Chunk has been consumed; we now must process the CRLF.
1393 // Note that we don't support trailer headers.
1394 if (prot->BuffUsed() < 2) return 1;
1395 if (prot->myBuffStart[0] != '\r' || prot->myBuffStart[1] != '\n') {
1396 prot->SendSimpleResp(400, NULL, NULL, (char *) "Invalid trailing chunk encoding.", 0, keepalive);
1397 return -1;
1398 }
1399 prot->BuffConsume(2);
1400 if (m_current_chunk_size == 0) {
1401 // All data has been sent. Turn off chunk processing and
1402 // set the bytes written and length appropriately; on next callback,
1403 // we will hit the close() block below.
1404 m_transfer_encoding_chunked = false;
1406 return ProcessHTTPReq();
1407 }
1408 m_current_chunk_size = -1;
1409 m_current_chunk_offset = 0;
1410 // If there is more data, we try to process the next chunk; otherwise, return
1411 if (!prot->BuffUsed()) return 1;
1412 }
1413 if (-1 == m_current_chunk_size) {
1414
1415 // Parse out the next chunk size.
1416 long long idx = 0;
1417 bool found_newline = false;
1418 // Set a maximum size of chunk we will allow
1419 // Nginx sets this to "NGX_MAX_OFF_T_VALUE", which is 9223372036854775807 (a some crazy number)
1420 // We set it to 1TB, which is 1099511627776
1421 // This is to prevent a malicious client from sending a very large chunk size
1422 // or a malformed chunk request.
1423 // 1TB in base-16 is 0x40000000000, so only allow 11 characters, plus the CRLF
1424 long long max_chunk_size_chars = std::min(static_cast<long long>(prot->BuffUsed()), static_cast<long long>(13));
1425 for (; idx < max_chunk_size_chars; idx++) {
1426 if (prot->myBuffStart[idx] == '\n') {
1427 found_newline = true;
1428 break;
1429 }
1430 }
1431 // If we found a new line, but it is the first character in the buffer (no chunk length)
1432 // or if the previous character is not a CR.
1433 if (found_newline && ((idx == 0) || prot->myBuffStart[idx-1] != '\r')) {
1434 prot->SendSimpleResp(400, NULL, NULL, (char *)"Invalid chunked encoding", 0, false);
1435 TRACE(REQ, "XrdHTTP PUT: Sending invalid chunk encoding. Start of chunk should have had a length, followed by a CRLF.");
1436 return -1;
1437 }
1438 if (found_newline) {
1439 char *endptr = NULL;
1440 std::string line_contents(prot->myBuffStart, idx);
1441 long long chunk_contents = strtol(line_contents.c_str(), &endptr, 16);
1442 // Chunk sizes can be followed by trailer information or CRLF
1443 if (*endptr != ';' && *endptr != '\r') {
1444 prot->SendSimpleResp(400, NULL, NULL, (char *)"Invalid chunked encoding", 0, false);
1445 TRACE(REQ, "XrdHTTP PUT: Sending invalid chunk encoding. Chunk size was not followed by a ';' or CR." << __LINE__);
1446 return -1;
1447 }
1448 m_current_chunk_size = chunk_contents;
1449 m_current_chunk_offset = 0;
1450 prot->BuffConsume(idx + 1);
1451 TRACE(REQ, "XrdHTTP PUT: next chunk from client will be " << m_current_chunk_size << " bytes");
1452 } else {
1453 // Need more data!
1454 return 1;
1455 }
1456 }
1457
1458 if (m_current_chunk_size == 0) {
1459 // All data has been sent. Invoke this routine again immediately to process CRLF
1460 return ProcessHTTPReq();
1461 } else {
1462 // At this point, we have a chunk size defined and should consume payload data
1463 memset(&xrdreq, 0, sizeof (xrdreq));
1464 xrdreq.write.requestid = htons(kXR_write);
1465 memcpy(xrdreq.write.fhandle, fhandle, 4);
1466
1467 long long chunk_bytes_remaining = m_current_chunk_size - m_current_chunk_offset;
1468 long long bytes_to_write = std::min(static_cast<long long>(prot->BuffUsed()),
1469 chunk_bytes_remaining);
1470
1471 xrdreq.write.offset = htonll(writtenbytes);
1472 xrdreq.write.dlen = htonl(bytes_to_write);
1473
1474 TRACEI(REQ, "XrdHTTP PUT: Writing chunk of size " << bytes_to_write << " starting with '" << *(prot->myBuffStart) << "'" << " with " << chunk_bytes_remaining << " bytes remaining in the chunk");
1475 if (!prot->Bridge->Run((char *) &xrdreq, prot->myBuffStart, bytes_to_write)) {
1476 mapXrdErrorToHttpStatus();
1477 return sendFooterError("Could not run write request on the bridge");
1478 }
1479 // If there are more bytes in the buffer, then immediately call us after the
1480 // write is finished; otherwise, wait for data.
1481 return (prot->BuffUsed() > chunk_bytes_remaining) ? 0 : 1;
1482 }
1483 } else if (writtenbytes < length) {
1484
1485
1486 // --------- WRITE
1487 memset(&xrdreq, 0, sizeof (xrdreq));
1488 xrdreq.write.requestid = htons(kXR_write);
1489 memcpy(xrdreq.write.fhandle, fhandle, 4);
1490
1491 long long bytes_to_read = std::min(static_cast<long long>(prot->BuffUsed()),
1493
1494 xrdreq.write.offset = htonll(writtenbytes);
1495 xrdreq.write.dlen = htonl(bytes_to_read);
1496
1497 TRACEI(REQ, "Writing " << bytes_to_read);
1498 if (!prot->Bridge->Run((char *) &xrdreq, prot->myBuffStart, bytes_to_read)) {
1499 mapXrdErrorToHttpStatus();
1500 return sendFooterError("Could not run write request on the bridge");
1501 }
1502
1503 if (writtenbytes + prot->BuffUsed() >= length)
1504 // Trigger an immediate recall after this request has finished
1505 return 0;
1506 else
1507 // We want to be invoked again after this request is finished
1508 // only if there is pending data
1509 return 1;
1510
1511
1512
1513 } else {
1514
1515 // --------- CLOSE
1516 memset(&xrdreq, 0, sizeof (ClientRequest));
1517 xrdreq.close.requestid = htons(kXR_close);
1518 memcpy(xrdreq.close.fhandle, fhandle, 4);
1519
1520
1521 if (!prot->Bridge->Run((char *) &xrdreq, 0, 0)) {
1522 mapXrdErrorToHttpStatus();
1523 return sendFooterError("Could not run close request on the bridge");
1524 }
1525
1526 // We have finished
1527 return 1;
1528
1529 }
1530
1531 }
1532
1533 break;
1534
1535 }
1537 {
1538 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);
1539 bool ret_keepalive = keepalive; // reset() clears keepalive
1540 reset();
1541 return ret_keepalive ? 1 : -1;
1542 }
1544 {
1545
1546
1547 switch (reqstate) {
1548
1549 case 0: // Stat()
1550 {
1551
1552
1553 // --------- STAT is always the first step
1554 memset(&xrdreq, 0, sizeof (ClientRequest));
1555 xrdreq.stat.requestid = htons(kXR_stat);
1556 std::string s = resourceplusopaque.c_str();
1557
1558
1559 l = resourceplusopaque.length() + 1;
1560 xrdreq.stat.dlen = htonl(l);
1561
1562 if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1563 prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1564 return -1;
1565 }
1566
1567 // We need to be invoked again to complete the request
1568 return 0;
1569 }
1570 default:
1571
1572 if (fileflags & kXR_isDir) {
1573 // --------- RMDIR
1574 memset(&xrdreq, 0, sizeof (ClientRequest));
1575 xrdreq.rmdir.requestid = htons(kXR_rmdir);
1576
1577 std::string s = resourceplusopaque.c_str();
1578
1579 l = s.length() + 1;
1580 xrdreq.rmdir.dlen = htonl(l);
1581
1582 if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1583 prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run rmdir request.", 0, false);
1584 return -1;
1585 }
1586 } else {
1587 // --------- DELETE
1588 memset(&xrdreq, 0, sizeof (ClientRequest));
1589 xrdreq.rm.requestid = htons(kXR_rm);
1590
1591 std::string s = resourceplusopaque.c_str();
1592
1593 l = s.length() + 1;
1594 xrdreq.rm.dlen = htonl(l);
1595
1596 if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1597 prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run rm request.", 0, false);
1598 return -1;
1599 }
1600 }
1601
1602
1603 // We don't want to be invoked again after this request is finished
1604 return 1;
1605
1606 }
1607
1608
1609
1610 }
1612 {
1613 prot->SendSimpleResp(501, NULL, NULL, (char *) "Request not supported yet.", 0, false);
1614
1615 return -1;
1616 }
1618 {
1619
1620
1621
1622 switch (reqstate) {
1623
1624 case 0: // Stat() and add the current item to the list of the things to send
1625 {
1626
1627 if (length > 0) {
1628 TRACE(REQ, "Reading request body " << length << " bytes.");
1629 char *p = 0;
1630 // We have to specifically read all the request body
1631
1632 if (prot->BuffgetData(length, &p, true) < length) {
1633 prot->SendSimpleResp(501, NULL, NULL, (char *) "Error in getting the PROPFIND request body.", 0, false);
1634 return -1;
1635 }
1636
1637 if ((depth > 1) || (depth < 0)) {
1638 prot->SendSimpleResp(501, NULL, NULL, (char *) "Invalid depth value.", 0, false);
1639 return -1;
1640 }
1641
1642
1643 parseBody(p, length);
1644 }
1645
1646
1647 // --------- STAT is always the first step
1648 memset(&xrdreq, 0, sizeof (ClientRequest));
1649 xrdreq.stat.requestid = htons(kXR_stat);
1650 std::string s = resourceplusopaque.c_str();
1651
1652
1653 l = resourceplusopaque.length() + 1;
1654 xrdreq.stat.dlen = htonl(l);
1655
1656 if (!prot->Bridge->Run((char *) &xrdreq, (char *) resourceplusopaque.c_str(), l)) {
1657 prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1658 return -1;
1659 }
1660
1661
1662 if (depth == 0) {
1663 // We don't need to be invoked again
1664 return 1;
1665 } else
1666 // We need to be invoked again to complete the request
1667 return 0;
1668
1669
1670
1671 break;
1672 }
1673
1674 default: // Dirlist()
1675 {
1676
1677 // --------- DIRLIST
1678 memset(&xrdreq, 0, sizeof (ClientRequest));
1679 xrdreq.dirlist.requestid = htons(kXR_dirlist);
1680
1681 std::string s = resourceplusopaque.c_str();
1682 xrdreq.dirlist.options[0] = kXR_dstat;
1683 //s += "?xrd.dirstat=1";
1684
1685 l = s.length() + 1;
1686 xrdreq.dirlist.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 }
1697
1698
1699 break;
1700 }
1702 {
1703
1704 // --------- MKDIR
1705 memset(&xrdreq, 0, sizeof (ClientRequest));
1706 xrdreq.mkdir.requestid = htons(kXR_mkdir);
1707
1708 std::string s = resourceplusopaque.c_str();
1709 xrdreq.mkdir.options[0] = (kXR_char) kXR_mkdirpath;
1710
1711 l = s.length() + 1;
1712 xrdreq.mkdir.dlen = htonl(l);
1713
1714 if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1715 prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1716 return -1;
1717 }
1718
1719 // We don't want to be invoked again after this request is finished
1720 return 1;
1721 }
1722 case XrdHttpReq::rtMOVE:
1723 {
1724 // Incase of a move cgi parameters present in the CGI str
1725 // are appended to the destination in case of a MOVE.
1726 if (resourceplusopaque != "") {
1727 int pos = resourceplusopaque.find("?");
1728 if (pos != STR_NPOS) {
1729 destination.append((destination.find("?") == std::string::npos) ? "?" : "&");
1730 destination.append(resourceplusopaque.c_str() + pos + 1);
1731 }
1732 }
1733
1734 // --------- MOVE
1735 memset(&xrdreq, 0, sizeof (ClientRequest));
1736 xrdreq.mv.requestid = htons(kXR_mv);
1737
1738 std::string s = resourceplusopaque.c_str();
1739 s += " ";
1740
1741 char buf[256];
1742 char *ppath;
1743 int port = 0;
1744 if (parseURL((char *) destination.c_str(), buf, port, &ppath)) {
1745 prot->SendSimpleResp(501, NULL, NULL, (char *) "Cannot parse destination url.", 0, false);
1746 return -1;
1747 }
1748
1749 char buf2[256];
1750 strcpy(buf2, host.c_str());
1751 char *pos = strchr(buf2, ':');
1752 if (pos) *pos = '\0';
1753
1754 // If we are a redirector we enforce that the host field is equal to
1755 // whatever was written in the destination url
1756 //
1757 // If we are a data server instead we cannot enforce anything, we will
1758 // just ignore the host part of the destination
1759 if ((prot->myRole == kXR_isManager) && strcmp(buf, buf2)) {
1760 prot->SendSimpleResp(501, NULL, NULL, (char *) "Only in-place renaming is supported for MOVE.", 0, false);
1761 return -1;
1762 }
1763
1764
1765
1766
1767 s += ppath;
1768
1769 l = s.length() + 1;
1770 xrdreq.mv.dlen = htonl(l);
1771 xrdreq.mv.arg1len = htons(resourceplusopaque.length());
1772
1773 if (!prot->Bridge->Run((char *) &xrdreq, (char *) s.c_str(), l)) {
1774 prot->SendSimpleResp(501, NULL, NULL, (char *) "Could not run request.", 0, false);
1775 return -1;
1776 }
1777
1778 // We don't want to be invoked again after this request is finished
1779 return 1;
1780
1781 }
1782 default:
1783 {
1784 prot->SendSimpleResp(501, NULL, NULL, (char *) "Request not supported.", 0, false);
1785 return -1;
1786 }
1787
1788 }
1789
1790 return 1;
1791}
#define kXR_isManager
@ kXR_open_wrto
Definition XProtocol.hh:469
@ kXR_delete
Definition XProtocol.hh:453
@ kXR_open_read
Definition XProtocol.hh:456
@ kXR_mkpath
Definition XProtocol.hh:460
@ kXR_seqio
Definition XProtocol.hh:468
@ kXR_new
Definition XProtocol.hh:455
@ kXR_retstat
Definition XProtocol.hh:463
@ kXR_dstat
Definition XProtocol.hh:240
@ kXR_read
Definition XProtocol.hh:125
@ kXR_mkdir
Definition XProtocol.hh:120
@ kXR_dirlist
Definition XProtocol.hh:116
@ kXR_rm
Definition XProtocol.hh:126
@ kXR_write
Definition XProtocol.hh:131
@ kXR_rmdir
Definition XProtocol.hh:127
@ kXR_mv
Definition XProtocol.hh:121
@ kXR_stat
Definition XProtocol.hh:129
@ kXR_close
Definition XProtocol.hh:115
@ kXR_mkdirpath
Definition XProtocol.hh:410
@ kXR_gw
Definition XProtocol.hh:444
@ kXR_ur
Definition XProtocol.hh:440
@ kXR_uw
Definition XProtocol.hh:441
@ kXR_gr
Definition XProtocol.hh:443
@ kXR_or
Definition XProtocol.hh:446
@ kXR_isDir
int kXR_int32
Definition XPtypes.hh:89
unsigned char kXR_char
Definition XPtypes.hh:65
#define DEBUG(x)
int parseURL(char *url, char *host, int &port, char **path)
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:95
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
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_req_digest, m_resource_with_digest, obfuscateAuth(), opaque, parseBody(), parseURL(), 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, 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 545 of file XrdHttpReq.cc.

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

References appendOpaque(), calcHashes(), encode_opaque(), encode_str(), keepalive, obfuscateAuth(), redirdest, request, reset(), resource, rtGET, 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 397 of file XrdHttpReq.cc.

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

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

2818 {
2819
2820 TRACE(REQ, " XrdHttpReq request ended.");
2821
2822 //if (xmlbody) xmlFreeDoc(xmlbody);
2823 readRangeHandler.reset();
2824 readClosing = false;
2825 closeAfterError = false;
2826 writtenbytes = 0;
2827 etext.clear();
2828 redirdest = "";
2829
2830 // // Here we should deallocate this
2831 // const struct iovec *iovP //!< pointer to data array
2832 // int iovN, //!< array count
2833 // int iovL, //!< byte count
2834 // bool final //!< true -> final result
2835
2836
2837 //xmlbody = 0;
2838 depth = 0;
2841 ralist.clear();
2842 ralist.shrink_to_fit();
2843
2844 request = rtUnset;
2845 resource = "";
2846 allheaders.clear();
2847
2848 // Reset the state of the request's digest request.
2849 m_req_digest.clear();
2850 m_digest_header.clear();
2851 m_req_cksum = nullptr;
2852
2854 m_user_agent = "";
2855 m_origin = "";
2856
2857 headerok = false;
2858 keepalive = true;
2859 length = 0;
2860 filesize = 0;
2861 depth = 0;
2862 sendcontinue = false;
2863
2864 m_transfer_encoding_chunked = false;
2865 m_current_chunk_size = -1;
2866 m_current_chunk_offset = 0;
2867
2868 m_trailer_headers = false;
2869 m_status_trailer = false;
2870
2872 reqstate = 0;
2873
2874 memset(&xrdreq, 0, sizeof (xrdreq));
2875 memset(&xrdresp, 0, sizeof (xrdresp));
2877
2878 etext.clear();
2879 redirdest = "";
2880
2881 stringresp = "";
2882
2883 host = "";
2884 destination = "";
2885 hdr2cgistr = "";
2886 m_appended_hdr2cgistr = false;
2887 m_appended_asize = false;
2888
2889 iovP = 0;
2890 iovN = 0;
2891 iovL = 0;
2892
2893
2894 if (opaque) delete(opaque);
2895 opaque = 0;
2896
2897 fopened = false;
2898
2899 final = false;
2900
2901 mScitag = -1;
2902}
@ kXR_noErrorYet
@ kXR_noResponsesYet
Definition XProtocol.hh:908
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.

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_req_cksum, m_req_digest, m_resource_with_digest, mScitag, opaque, ralist, readClosing, readRangeHandler, redirdest, reqstate, request, resource, rtUnset, sendcontinue, stringresp, TRACE, writtenbytes, xrderrcode, xrdreq, and xrdresp.

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

+ Here is the caller graph for this function:

◆ setTransferStatusHeader()

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

Definition at line 2122 of file XrdHttpReq.cc.

2122 {
2123 if (m_status_trailer) {
2124 if (header.empty()) {
2125 header += "Trailer: X-Transfer-Status";
2126 } else {
2127 header += "\r\nTrailer: X-Transfer-Status";
2128 }
2129 }
2130}

◆ userAgent()

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

Definition at line 259 of file XrdHttpReq.hh.

259{return m_user_agent;}

Member Data Documentation

◆ allheaders

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

Definition at line 268 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ closeAfterError

bool XrdHttpReq::closeAfterError

Definition at line 287 of file XrdHttpReq.hh.

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

◆ depth

int XrdHttpReq::depth

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

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

◆ etext

std::string XrdHttpReq::etext

Definition at line 332 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ fhandle

char XrdHttpReq::fhandle[4]

Definition at line 346 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filectime

long XrdHttpReq::filectime

Definition at line 345 of file XrdHttpReq.hh.

◆ fileflags

long XrdHttpReq::fileflags

Definition at line 343 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq().

◆ filemodtime

long XrdHttpReq::filemodtime

Definition at line 344 of file XrdHttpReq.hh.

◆ filesize

long long XrdHttpReq::filesize

Definition at line 342 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ final

bool XrdHttpReq::final

true -> final result

Definition at line 339 of file XrdHttpReq.hh.

◆ fopened

bool XrdHttpReq::fopened

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

Referenced by XrdHttpReq(), and reset().

◆ host

std::string XrdHttpReq::host

The host field specified in the req.

Definition at line 295 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ iovL

int XrdHttpReq::iovL

byte count

Definition at line 338 of file XrdHttpReq.hh.

Referenced by Data(), and reset().

◆ iovN

int XrdHttpReq::iovN

array count

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

Referenced by Data(), and reset().

◆ keepalive

bool XrdHttpReq::keepalive

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

316{false};

Referenced by ProcessHTTPReq(), and reset().

◆ m_appended_hdr2cgistr

bool XrdHttpReq::m_appended_hdr2cgistr

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

Referenced by reset().

◆ m_origin

std::string XrdHttpReq::m_origin

Definition at line 360 of file XrdHttpReq.hh.

Referenced by parseLine(), and reset().

◆ m_req_cksum

XrdHttpChecksumHandler::XrdHttpChecksumRawPtr XrdHttpReq::m_req_cksum = nullptr

The checksum that was ran for this request.

Definition at line 303 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ m_req_digest

std::string XrdHttpReq::m_req_digest

The requested digest type.

Definition at line 300 of file XrdHttpReq.hh.

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

◆ m_resource_with_digest

XrdOucString XrdHttpReq::m_resource_with_digest

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

Definition at line 308 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ mScitag

int XrdHttpReq::mScitag

Definition at line 358 of file XrdHttpReq.hh.

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

◆ opaque

XrdOucEnv* XrdHttpReq::opaque

The opaque data, after parsing.

Definition at line 273 of file XrdHttpReq.hh.

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

◆ ralist

std::vector<readahead_list> XrdHttpReq::ralist

Definition at line 241 of file XrdHttpReq.hh.

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

◆ readClosing

bool XrdHttpReq::readClosing

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

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

◆ redirdest

XrdOucString XrdHttpReq::redirdest

Definition at line 333 of file XrdHttpReq.hh.

Referenced by Redir(), and reset().

◆ reqstate

int XrdHttpReq::reqstate

State machine to talk to the bridge.

Definition at line 353 of file XrdHttpReq.hh.

Referenced by ProcessHTTPReq(), and reset().

◆ request

ReqType XrdHttpReq::request

The request we got.

Definition at line 263 of file XrdHttpReq.hh.

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

◆ requestverb

std::string XrdHttpReq::requestverb

Definition at line 264 of file XrdHttpReq.hh.

Referenced by parseFirstLine().

◆ resource

XrdOucString XrdHttpReq::resource

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

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

◆ rwOpPartialDone

unsigned int XrdHttpReq::rwOpPartialDone

Definition at line 324 of file XrdHttpReq.hh.

◆ sendcontinue

bool XrdHttpReq::sendcontinue

Definition at line 292 of file XrdHttpReq.hh.

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

◆ stringresp

std::string XrdHttpReq::stringresp

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

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

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

◆ xrderrcode

XErrorCode XrdHttpReq::xrderrcode

Definition at line 331 of file XrdHttpReq.hh.

Referenced by Error(), and reset().

◆ xrdreq

ClientRequest XrdHttpReq::xrdreq

The last issued xrd request, often pending.

Definition at line 327 of file XrdHttpReq.hh.

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

◆ xrdresp

XResponseType XrdHttpReq::xrdresp

The last response data we got.

Definition at line 330 of file XrdHttpReq.hh.

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


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