Logo ROOT   6.07/09
Reference Guide
THttpCallArg.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 21/05/2015
3 
4 #include "THttpCallArg.h"
5 
6 #include <string.h>
7 #include "RZip.h"
8 #include "TNamed.h"
9 
10 //////////////////////////////////////////////////////////////////////////
11 // //
12 // THttpCallArg //
13 // //
14 // Contains arguments for single HTTP call //
15 // Must be used in THttpEngine to process incoming http requests //
16 // //
17 //////////////////////////////////////////////////////////////////////////
18 
20 
21 ////////////////////////////////////////////////////////////////////////////////
22 /// constructor
23 
25  TObject(),
26  fTopName(),
27  fMethod(),
28  fPathName(),
29  fFileName(),
30  fUserName(),
31  fQuery(),
32  fPostData(0),
33  fPostDataLength(0),
34  fWSHandle(0),
35  fContentType(),
36  fRequestHeader(),
37  fHeader(),
38  fContent(),
39  fZipping(0),
40  fBinData(0),
41  fBinDataLength(0)
42 {
43 }
44 
45 ////////////////////////////////////////////////////////////////////////////////
46 /// destructor
47 
49 {
50  if (fPostData) {
51  free(fPostData);
52  fPostData = 0;
53  }
54 
55  if (fWSHandle) {
56  delete fWSHandle;
57  fWSHandle = 0;
58  }
59 
60  if (fBinData) {
61  free(fBinData);
62  fBinData = 0;
63  }
64 }
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// method used to get or set http header in the string buffer
68 /// Header has following format:
69 /// field1 : value1\\r\\n
70 /// field2 : value2\\r\\n
71 /// Such format corresponds to header format in HTTP requests
72 
73 TString THttpCallArg::AccessHeader(TString& buf, const char* name, const char* value, Bool_t doing_set)
74 {
75  if (name==0) return TString();
76 
77  Int_t curr = 0;
78 
79  while (curr < buf.Length()-2) {
80 
81  Int_t next = buf.Index("\r\n", curr);
82  if (next == kNPOS) break; // should never happen
83 
84  if (buf.Index(name, curr) != curr) {
85  curr = next + 2;
86  continue;
87  }
88 
89  if ((value==0) && doing_set) {
90  // special case - empty value means that field must be removed completely
91  buf.Remove(curr, next-curr+2);
92  return TString();
93  }
94 
95  curr += strlen(name);
96  while ((curr < next) && (buf[curr] != ':')) curr++;
97  curr++;
98  while ((curr < next) && (buf[curr] == ' ')) curr++;
99 
100  if (value==0) return buf(curr, next-curr);
101  buf.Remove(curr, next-curr);
102  buf.Insert(curr, value);
103  return TString(value);
104  }
105 
106  if (value==0) return TString();
107 
108  buf.Append(TString::Format("%s: %s\r\n", name, value));
109  return TString(value);
110 }
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 /// method used to counter number of headers or returns name of specified header
114 
116 {
117  Int_t curr(0), cnt(0);
118 
119  while (curr < buf.Length()-2) {
120 
121  Int_t next = buf.Index("\r\n", curr);
122  if (next == kNPOS) break; // should never happen
123 
124  if (cnt == number) {
125  // we should extract name of header
126  Int_t separ = curr + 1;
127  while ((separ < next) && (buf[separ] != ':')) separ++;
128  return buf(curr, separ-curr);
129  }
130 
131  curr = next + 2;
132  cnt++;
133  }
134 
135  // return total number of headers
136  if (number == -1111) return TString::Format("%d", cnt);
137  return TString();
138 }
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// set data, posted with the request
142 /// buffer should be allocated with malloc(length+1) call,
143 /// while last byte will be set to 0
144 /// Than one could use post data as null-terminated string
145 
146 void THttpCallArg::SetPostData(void *data, Long_t length)
147 {
148  if (fPostData) free(fPostData);
149  if (data!=0) *(((char*) data) + length) = 0;
150  fPostData = data;
151  fPostDataLength = length;
152 }
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 /// assign websocket handle with HTTP call
156 
158 {
159  if (fWSHandle) delete fWSHandle;
160  fWSHandle = handle;
161 }
162 
163 ////////////////////////////////////////////////////////////////////////////////
164 /// takeout websocket handle with HTTP call
165 /// can be done only once
166 
168 {
169  TNamed* res = fWSHandle;
170  fWSHandle = 0;
171  return res;
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// set binary data, which will be returned as reply body
176 
177 void THttpCallArg::SetBinData(void *data, Long_t length)
178 {
179  if (fBinData) free(fBinData);
180  fBinData = data;
181  fBinDataLength = length;
182 
183  // string content must be cleared in any case
184  fContent.Clear();
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// set complete path of requested http element
189 /// For instance, it could be "/folder/subfolder/get.bin"
190 /// Here "/folder/subfolder/" is element path and "get.bin" requested file.
191 /// One could set path and file name separately
192 
193 void THttpCallArg::SetPathAndFileName(const char *fullpath)
194 {
195  fPathName.Clear();
196  fFileName.Clear();
197 
198  if (fullpath == 0) return;
199 
200  const char *rslash = strrchr(fullpath, '/');
201  if (rslash == 0) {
202  fFileName = fullpath;
203  } else {
204  while ((fullpath != rslash) && (*fullpath == '/')) fullpath++;
205  fPathName.Append(fullpath, rslash - fullpath);
206  if (fPathName == "/") fPathName.Clear();
207  fFileName = rslash + 1;
208  }
209 }
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 /// return specified header
213 
215 {
216  if ((name == 0) || (*name == 0)) return TString();
217 
218  if (strcmp(name,"Content-Type") == 0) return fContentType;
219  if (strcmp(name,"Content-Length") == 0) return TString::Format("%ld", GetContentLength());
220 
221  return AccessHeader(fHeader, name);
222 }
223 
224 ////////////////////////////////////////////////////////////////////////////////
225 /// Set name: value pair to reply header
226 /// Content-Type field handled separately - one should use SetContentType() method
227 /// Content-Length field cannot be set at all;
228 
229 void THttpCallArg::AddHeader(const char *name, const char *value)
230 {
231  if ((name == 0) || (*name == 0) || (strcmp(name,"Content-Length") == 0)) return;
232 
233  if (strcmp(name,"Content-Type") == 0)
234  SetContentType(value);
235  else
236  AccessHeader(fHeader, name, value, kTRUE);
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// fill HTTP header
241 
242 void THttpCallArg::FillHttpHeader(TString &hdr, const char *kind)
243 {
244  if (kind == 0) kind = "HTTP/1.1";
245 
246  if ((fContentType.Length() == 0) || Is404()) {
247  hdr.Form("%s 404 Not Found\r\n"
248  "Content-Length: 0\r\n"
249  "Connection: close\r\n\r\n", kind);
250  } else {
251  hdr.Form("%s 200 OK\r\n"
252  "Content-Type: %s\r\n"
253  "Connection: keep-alive\r\n"
254  "Content-Length: %ld\r\n"
255  "%s\r\n",
256  kind,
257  GetContentType(),
259  fHeader.Data());
260  }
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// compress reply data with gzip compression
265 
267 {
268  char *objbuf = (char *) GetContent();
269  Long_t objlen = GetContentLength();
270 
271  unsigned long objcrc = R__crc32(0, NULL, 0);
272  objcrc = R__crc32(objcrc, (const unsigned char *) objbuf, objlen);
273 
274  // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
275  Int_t buflen = 10 + objlen + 8;
276  if (buflen < 512) buflen = 512;
277 
278  void *buffer = malloc(buflen);
279 
280  char *bufcur = (char *) buffer;
281 
282  *bufcur++ = 0x1f; // first byte of ZIP identifier
283  *bufcur++ = 0x8b; // second byte of ZIP identifier
284  *bufcur++ = 0x08; // compression method
285  *bufcur++ = 0x00; // FLAG - empty, no any file names
286  *bufcur++ = 0; // empty timestamp
287  *bufcur++ = 0; //
288  *bufcur++ = 0; //
289  *bufcur++ = 0; //
290  *bufcur++ = 0; // XFL (eXtra FLags)
291  *bufcur++ = 3; // OS 3 means Unix
292  //strcpy(bufcur, "item.json");
293  //bufcur += strlen("item.json")+1;
294 
295  char dummy[8];
296  memcpy(dummy, bufcur - 6, 6);
297 
298  // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
299  unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, objbuf, objlen);
300 
301  memcpy(bufcur - 6, dummy, 6);
302 
303  bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
304 
305  *bufcur++ = objcrc & 0xff; // CRC32
306  *bufcur++ = (objcrc >> 8) & 0xff;
307  *bufcur++ = (objcrc >> 16) & 0xff;
308  *bufcur++ = (objcrc >> 24) & 0xff;
309 
310  *bufcur++ = objlen & 0xff; // original data length
311  *bufcur++ = (objlen >> 8) & 0xff; // original data length
312  *bufcur++ = (objlen >> 16) & 0xff; // original data length
313  *bufcur++ = (objlen >> 24) & 0xff; // original data length
314 
315  SetBinData(buffer, bufcur - (char *) buffer);
316 
317  SetEncoding("gzip");
318 
319  return kTRUE;
320 }
void SetWSHandle(TNamed *handle)
assign websocket handle with HTTP call
Ssiz_t Length() const
Definition: TString.h:390
Long_t GetContentLength() const
Definition: THttpCallArg.h:327
Bool_t Is404() const
Definition: THttpCallArg.h:310
Basic string class.
Definition: TString.h:137
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
void * fBinData
indicate if content should be zipped
Definition: THttpCallArg.h:45
#define malloc
Definition: civetweb.c:818
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:592
void SetContentType(const char *typ)
Definition: THttpCallArg.h:207
const void * GetContent() const
Definition: THttpCallArg.h:332
const char * Data() const
Definition: TString.h:349
void SetEncoding(const char *typ)
Definition: THttpCallArg.h:261
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString...
Definition: TString.cxx:2335
void SetPostData(void *data, Long_t length)
set data, posted with the request buffer should be allocated with malloc(length+1) call...
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
void SetPathAndFileName(const char *fullpath)
set complete path of requested http element For instance, it could be "/folder/subfolder/get.bin" Here "/folder/subfolder/" is element path and "get.bin" requested file.
TString fContentType
condition used to wait for processing
Definition: THttpCallArg.h:39
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1140
TString fPathName
request method like GET or POST
Definition: THttpCallArg.h:27
TString & Append(const char *cs)
Definition: TString.h:492
TNamed * fWSHandle
length of binary data
Definition: THttpCallArg.h:35
Long_t fPostDataLength
binary data received with post request
Definition: THttpCallArg.h:33
Long_t fBinDataLength
binary data, assigned with http call
Definition: THttpCallArg.h:46
void SetBinData(void *data, Long_t length)
set binary data, which will be returned as reply body
TString AccessHeader(TString &buf, const char *name, const char *value=0, Bool_t doing_set=kFALSE)
method used to get or set http header in the string buffer Header has following format: field1 : valu...
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2322
void * fPostData
additional arguments
Definition: THttpCallArg.h:32
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
long Long_t
Definition: RtypesCore.h:50
#define ClassImp(name)
Definition: Rtypes.h:279
TString CountHeader(const TString &buf, Int_t number=-1111) const
method used to counter number of headers or returns name of specified header
TString fHeader
complete header, provided with request
Definition: THttpCallArg.h:41
#define free
Definition: civetweb.c:821
static RooMathCoreReg dummy
TNamed * TakeWSHandle()
takeout websocket handle with HTTP call can be done only once
Mother of all ROOT objects.
Definition: TObject.h:44
TString fContent
response header like ContentEncoding, Cache-Control and so on
Definition: THttpCallArg.h:42
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
const Ssiz_t kNPOS
Definition: Rtypes.h:115
#define NULL
Definition: Rtypes.h:82
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
const Bool_t kTRUE
Definition: Rtypes.h:91
~THttpCallArg()
destructor
TString fFileName
item path
Definition: THttpCallArg.h:28
char name[80]
Definition: TGX11.cxx:109
const char * cnt
Definition: TXMLSetup.cxx:75
Bool_t CompressWithGzip()
compress reply data with gzip compression
TString GetHeader(const char *name)
return specified header
void FillHttpHeader(TString &buf, const char *header=0)
fill HTTP header
const char * GetContentType() const
Definition: THttpCallArg.h:320