XRootD
XrdHttpReq.hh
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // This file is part of XrdHTTP: A pragmatic implementation of the
3 // HTTP/WebDAV protocol for the Xrootd framework
4 //
5 // Copyright (c) 2013 by European Organization for Nuclear Research (CERN)
6 // Author: Fabrizio Furano <furano@cern.ch>
7 // File Date: Nov 2012
8 //------------------------------------------------------------------------------
9 // XRootD is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Lesser General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // XRootD is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public License
20 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
21 //------------------------------------------------------------------------------
22 
23 
24 
25 
26 
27 
28 
38 #ifndef XRDHTTPREQ_HH
39 #define XRDHTTPREQ_HH
40 
41 #include "XProtocol/XProtocol.hh"
44 #include "XrdOuc/XrdOucString.hh"
46 #include "XrdHttpMonState.hh"
47 
48 #include <chrono>
49 #include <map>
50 #include <string>
51 #include <vector>
52 
53 struct DirListInfo {
54  std::string path;
55  long long size;
56  long id;
57  long flags;
58  long modtime;
59 };
60 
61 
62 class XrdHttpProtocol;
63 class XrdOucEnv;
64 
66 
67 public:
68  // ----------------
69  // Description of the request. The header/body parsing
70  // is supposed to populate these fields, for fast access while
71  // processing the request
72 
74  // Any changes here should also reflect in XrdHttpMon::verbCountersSchema to capture statistics of requests by verb
75  // The count and order or verbs listed should be consistent with the monitoring counters
76  enum ReqType : int {
77  rtUnset = -1,
78  rtUnknown = 0,
91  rtCount
92  };
93 
94 private:
95  // HTTP response parameters to be sent back to the user
96  int httpStatusCode{-1};
97 
98  // Stores the first response that was sent as part of the Response Header
99  // Used when staus code is updated after for e.g. Chunked Response + X-Transfer-Status request
100  int initialStatusCode{-1};
101 
102  // HTTP Error code for the response
103  // e.g. 8.1, 8.3.1, etc.
104  // https://twiki.cern.ch/twiki/bin/view/LCG/WebdavErrorImprovement
105  std::string httpErrorCode;
106  // HTTP response text with following format:
107  // Severity: ErrorCode: free-style text message
108  // Severity being OK, WARNING, or ERROR
109  // ErrorCode being a decimal numeric plus dot string, i.e. n or n.m or n.m.l,
110  // etc. free-style text message any UTF-8 string
111  // Optionally, it also contains the trailer headers whereever applicable
112  // e.g. X-Transfer-Status: 200: OK
113  // or X-Transfer-Status: 500: ERROR: <error message>: <additional text>
114  std::string httpErrorBody;
115 
116 
117  // The value of the user agent, if specified
118  std::string m_user_agent;
119 
120  // Whether transfer encoding was requested.
121  bool m_transfer_encoding_chunked;
122  long long m_current_chunk_offset;
123  long long m_current_chunk_size;
124 
125  // Whether trailer headers were enabled
126  bool m_trailer_headers{false};
127 
128  // Whether the client understands our special status trailer.
129  // The status trailer allows us to report when an IO error occurred
130  // after a response body has started
131  bool m_status_trailer{false};
132 
133  int parseHost(char *);
134 
135  void parseScitag(const std::string & val);
136 
137  //xmlDocPtr xmlbody; /* the resulting document tree */
138  XrdHttpProtocol *prot;
139 
140  void clientMarshallReadAheadList(int nitems);
141  void clientUnMarshallReadAheadList(int nitems);
142 
143 
144  void getfhandle();
145 
146  // Process the checksum response and return a header that should
147  // be included in the response.
148  int PostProcessChecksum(std::string &digest_header);
149 
150  // Process the listing request of a GET request against a directory
151  // - final_: True if this is the last entry in the listing.
152  int PostProcessListing(bool final_);
153 
154  // Send the response for a GET request for a file read (i.e., not a directory)
155  // Invoked after the open is successful but before the first read is issued.
156  int ReturnGetHeaders();
157 
163  int PostProcessHTTPReq(bool final = false);
164 
165  // Parse a resource string, typically a filename, setting the resource field and the opaque data
166  void parseResource(char *url);
167 
168  // Set Webdav Error messages
169  void generateWebdavErrMsg();
170 
171  // Sanitize the resource from http[s]://[host]/ questionable prefix
172  void sanitizeResourcePfx();
173 
174  // parses the iovN data pointers elements as either a kXR_read or kXR_readv
175  // response and fills out a XrdHttpIOList with the corresponding length and
176  // buffer pointers. File offsets from kXR_readv responses are not recorded.
177  void getReadResponse(XrdHttpIOList &received);
178 
179  // notifies the range handler of receipt of bytes and sends the client
180  // the data.
181  int sendReadResponseSingleRange(const XrdHttpIOList &received);
182 
183  // notifies the range handler of receipt of bytes and sends the client
184  // the data and necessary headers, assuming multipart/byteranges content type.
185  int sendReadResponsesMultiRanges(const XrdHttpIOList &received);
186 
187  // If requested by the client, sends any I/O errors that occur during the transfer
188  // into a footer.
189  int sendFooterError(const std::string &);
190 
191  // Set the age header from the file modification time
192  void addAgeHeader(std::string & headers);
193 
194  // Set the ETag header containing union of stat.st_ino and stat.st_dev
195  // See XrdXrootdProtocol::StatGen() for the full definition of etag value.
196  void addETagHeader(std::string & headers);
197 
204  int prepareChecksumQuery(XrdHttpChecksumHandler::XrdHttpChecksumRawPtr & outCksum, XrdOucString & outResourceDigestOpaque);
205 
206 public:
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  };
220 
221  virtual ~XrdHttpReq();
222 
223  virtual void reset();
224 
225  int getInitialStatusCode() { return initialStatusCode;}
226  int getHttpStatusCode() { return httpStatusCode;}
227 
228  void setHttpStatusCode(int code) {
229  httpStatusCode = code;
230  if (initialStatusCode < 0 && code >= 200 ) {
231  initialStatusCode = code;
232  }
233  }
234 
236  int parseLine(char *line, int len);
237 
239  int parseFirstLine(char *line, int len);
240 
242  int parseBody(char *body, long long len);
243 
245  int ReqReadV(const XrdHttpIOList &cl);
246  std::vector<readahead_list> ralist;
247 
249  std::string buildPartialHdr(long long bytestart, long long byteend, long long filesize, char *token);
250 
252  std::string buildPartialHdrEnd(char *token);
253 
254  // Appends the opaque info that we have
255  // NOTE: this function assumes that the strings are unquoted, and will quote them
256  void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow);
257 
258  void addCgi(const std::string & key, const std::string & value);
259 
260  // Set the transfer status header, if requested by the client
261  void setTransferStatusHeader(std::string &header);
262 
263  // Return the current user agent; if none has been specified, returns an empty string
264  const std::string &userAgent() const {return m_user_agent;}
265 
266 
269  std::string requestverb;
270 
271  // We have to keep the headers for possible further processing
272  // by external plugins
273  std::map<std::string, std::string> allheaders;
274 
281 
282 
284  bool headerok;
285 
289 
290  // Indication that there was a read error and the next
291  // request processing state should cleanly close the file.
293 
294  bool keepalive;
295  long long length; // Total size from client for PUT; total length of response TO client for GET.
296  int depth;
298 
300  std::string host;
302  std::string destination;
303 
305  std::string m_want_digest;
306 
309 
315  std::string m_digest_header;
316 
318  std::string hdr2cgistr;
321  bool m_appended_asize{false};
322 
323  //
324  // Area for coordinating request and responses to/from the bridge
325  //
326 
327 
329  unsigned int rwOpDone, rwOpPartialDone;
330 
333 
337  std::string etext;
339 
341  const struct iovec *iovP;
342  int iovN;
343  int iovL;
344  bool final;
345 
346  // The latest stat info got from the xrd layer
347  long long etagval;
348  long long filesize;
349  long fileflags;
351  long filectime;
352  char fhandle[4];
353  bool fopened;
354 
356  std::string stringresp;
357 
359  int reqstate;
360 
362  long long writtenbytes;
363 
364  int mScitag;
365 
366  std::string m_origin;
367 
368  std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::time_point::min();
369 
371  std::map<std::string,std::string> m_repr_digest;
372 
375  std::map<std::string,uint8_t> m_want_repr_digest;
376 
378 
384  int ProcessHTTPReq();
385 
386 
387  // ------------
388  // Items inherited from the Bridge class
389  //
390 
391  //-----------------------------------------------------------------------------
417  //-----------------------------------------------------------------------------
418 
419  virtual bool Data(XrdXrootd::Bridge::Context &info,
420  const
421  struct iovec *iovP,
422  int iovN,
423  int iovL,
424  bool final
425  );
426 
427  //-----------------------------------------------------------------------------
437  //-----------------------------------------------------------------------------
438 
439  virtual bool Done(XrdXrootd::Bridge::Context &info);
440 
441 
442  //-----------------------------------------------------------------------------
455  //-----------------------------------------------------------------------------
456 
457  virtual bool Error(XrdXrootd::Bridge::Context &info,
458  int ecode,
459  const char *etext
460  );
461 
462  //-----------------------------------------------------------------------------
475  //-----------------------------------------------------------------------------
476 
477  virtual int File(XrdXrootd::Bridge::Context &info,
478  int dlen
479  );
480 
481  //-----------------------------------------------------------------------------
494  //-----------------------------------------------------------------------------
495 
496  virtual bool Redir(XrdXrootd::Bridge::Context &info,
497  int port,
498  const char *hname
499  );
500 
501 };
502 
503 
504 
505 void trim(std::string &str);
506 
507 #endif /* XRDHTTPREQ_HH */
508 
XErrorCode
Definition: XProtocol.hh:1031
XResponseType
Definition: XProtocol.hh:940
XrdHttpMonState
long long size
Definition: XrdHttpReq.hh:55
void trim(std::string &str)
Definition: XrdHttpReq.cc:78
std::string path
Definition: XrdHttpReq.hh:54
long modtime
Definition: XrdHttpReq.hh:58
std::vector< XrdOucIOVec2 > XrdHttpIOList
int reqstate
State machine to talk to the bridge.
Definition: XrdHttpReq.hh:359
char fhandle[4]
Definition: XrdHttpReq.hh:352
int ReqReadV(const XrdHttpIOList &cl)
Prepare the buffers for sending a readv request.
Definition: XrdHttpReq.cc:407
int getHttpStatusCode()
Definition: XrdHttpReq.hh:226
bool keepalive
Definition: XrdHttpReq.hh:294
unsigned int rwOpPartialDone
Definition: XrdHttpReq.hh:329
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
Definition: XrdHttpReq.hh:246
long long length
Definition: XrdHttpReq.hh:295
std::string destination
The destination field specified in the req.
Definition: XrdHttpReq.hh:302
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:276
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:284
std::map< std::string, uint8_t > m_want_repr_digest
Definition: XrdHttpReq.hh:375
std::string m_digest_header
The computed digest for the HTTP response header.
Definition: XrdHttpReq.hh:315
std::string etext
Definition: XrdHttpReq.hh:337
std::string stringresp
If we want to give a string as a response, we compose it here.
Definition: XrdHttpReq.hh:356
XResponseType xrdresp
The last response data we got.
Definition: XrdHttpReq.hh:335
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.
Definition: XrdHttpReq.hh:371
std::string requestverb
Definition: XrdHttpReq.hh:269
ReqType request
The request we got.
Definition: XrdHttpReq.hh:268
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:881
bool closeAfterError
Definition: XrdHttpReq.hh:292
long long writtenbytes
In a long write, we track where we have arrived.
Definition: XrdHttpReq.hh:362
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:278
long fileflags
Definition: XrdHttpReq.hh:349
int iovL
byte count
Definition: XrdHttpReq.hh:343
bool fopened
Definition: XrdHttpReq.hh:353
const struct iovec * iovP
The latest data chunks got from the xrd layer. These are valid only inside the callbacks!
Definition: XrdHttpReq.hh:341
virtual ~XrdHttpReq()
Definition: XrdHttpReq.cc:112
XrdOucString resourceplusopaque
The resource specified by the request, including all the opaque data.
Definition: XrdHttpReq.hh:280
virtual bool Data(XrdXrootd::Bridge::Context &info, const struct iovec *iovP, int iovN, int iovL, bool final)
Definition: XrdHttpReq.cc:462
long filectime
Definition: XrdHttpReq.hh:351
std::string hdr2cgistr
Additional opaque info that may come from the hdr2cgi directive.
Definition: XrdHttpReq.hh:318
virtual bool Done(XrdXrootd::Bridge::Context &info)
the result context
Definition: XrdHttpReq.cc:508
std::string host
The host field specified in the req.
Definition: XrdHttpReq.hh:300
long filemodtime
Definition: XrdHttpReq.hh:350
int parseFirstLine(char *line, int len)
Parse the first line of the header.
Definition: XrdHttpReq.cc:275
XrdOucString redirdest
Definition: XrdHttpReq.hh:338
void setHttpStatusCode(int code)
Definition: XrdHttpReq.hh:228
std::string m_origin
Definition: XrdHttpReq.hh:366
ReqType
These are the HTTP/DAV requests that we support.
Definition: XrdHttpReq.hh:76
int parseLine(char *line, int len)
Parse the header.
Definition: XrdHttpReq.cc:118
std::string buildPartialHdrEnd(char *token)
Build the closing part for a multipart response.
Definition: XrdHttpReq.cc:454
XrdHttpChecksumHandler::XrdHttpChecksumRawPtr m_req_cksum
The checksum that was ran for this request.
Definition: XrdHttpReq.hh:308
std::string m_want_digest
The requested digest type.
Definition: XrdHttpReq.hh:305
void setTransferStatusHeader(std::string &header)
Definition: XrdHttpReq.cc:2031
bool m_appended_hdr2cgistr
Definition: XrdHttpReq.hh:319
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
Definition: XrdHttpReq.cc:652
int iovN
array count
Definition: XrdHttpReq.hh:342
XrdHttpReq(XrdHttpProtocol *protinstance, const XrdHttpReadRangeHandler::Configuration &rcfg)
Definition: XrdHttpReq.hh:207
bool m_appended_asize
Track whether we already appended the oss.asize argument for PUTs.
Definition: XrdHttpReq.hh:321
XrdOucString m_resource_with_digest
Definition: XrdHttpReq.hh:313
long long filesize
Definition: XrdHttpReq.hh:348
bool readClosing
Definition: XrdHttpReq.hh:288
std::chrono::steady_clock::time_point startTime
Definition: XrdHttpReq.hh:368
long long etagval
Definition: XrdHttpReq.hh:347
virtual bool Redir(XrdXrootd::Bridge::Context &info, int port, const char *hname)
Definition: XrdHttpReq.cc:555
XErrorCode xrderrcode
Definition: XrdHttpReq.hh:336
virtual int File(XrdXrootd::Bridge::Context &info, int dlen)
Definition: XrdHttpReq.cc:484
std::map< std::string, std::string > allheaders
Definition: XrdHttpReq.hh:273
int getInitialStatusCode()
Definition: XrdHttpReq.hh:225
unsigned int rwOpDone
To coordinate multipart responses across multiple calls.
Definition: XrdHttpReq.hh:329
void addCgi(const std::string &key, const std::string &value)
Definition: XrdHttpReq.cc:760
bool sendcontinue
Definition: XrdHttpReq.hh:297
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:332
const std::string & userAgent() const
Definition: XrdHttpReq.hh:264
XrdHttpMonState monState
Definition: XrdHttpReq.hh:377
std::string buildPartialHdr(long long bytestart, long long byteend, long long filesize, char *token)
Build a partial header for a multipart response.
Definition: XrdHttpReq.cc:444
XrdHttpReadRangeHandler readRangeHandler
Tracking the next ranges of data to read during GET.
Definition: XrdHttpReq.hh:287
virtual void reset()
Definition: XrdHttpReq.cc:2713
virtual bool Error(XrdXrootd::Bridge::Context &info, int ecode, const char *etext)
Definition: XrdHttpReq.cc:525