Logo ROOT   6.16/01
Reference Guide
THttpCallArg.cxx
Go to the documentation of this file.
1// $Id$
2// Author: Sergey Linev 21/05/2015
3
4/*************************************************************************
5 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "THttpCallArg.h"
13
14#include <string.h>
15#include "RZip.h"
16#include "THttpWSEngine.h"
17
18//////////////////////////////////////////////////////////////////////////
19// //
20// THttpCallArg //
21// //
22// Contains arguments for single HTTP call //
23// Must be used in THttpEngine to process incoming http requests //
24// //
25//////////////////////////////////////////////////////////////////////////
26
28
29////////////////////////////////////////////////////////////////////////////////
30/// destructor
31
33{
34}
35
36////////////////////////////////////////////////////////////////////////////////
37/// method used to get or set http header in the string buffer
38/// Header has following format:
39/// field1 : value1\\r\\n
40/// field2 : value2\\r\\n
41/// Such format corresponds to header format in HTTP requests
42
43TString THttpCallArg::AccessHeader(TString &buf, const char *name, const char *value, Bool_t doing_set)
44{
45 if (name == 0)
46 return TString();
47
48 Int_t curr = 0;
49
50 while (curr < buf.Length() - 2) {
51
52 Int_t next = buf.Index("\r\n", curr);
53 if (next == kNPOS)
54 break; // should never happen
55
56 if (buf.Index(name, curr) != curr) {
57 curr = next + 2;
58 continue;
59 }
60
61 if ((value == 0) && doing_set) {
62 // special case - empty value means that field must be removed completely
63 buf.Remove(curr, next - curr + 2);
64 return TString();
65 }
66
67 curr += strlen(name);
68 while ((curr < next) && (buf[curr] != ':'))
69 curr++;
70 curr++;
71 while ((curr < next) && (buf[curr] == ' '))
72 curr++;
73
74 if (value == 0)
75 return buf(curr, next - curr);
76 buf.Remove(curr, next - curr);
77 buf.Insert(curr, value);
78 return TString(value);
79 }
80
81 if (value == 0)
82 return TString();
83
84 buf.Append(TString::Format("%s: %s\r\n", name, value));
85 return TString(value);
86}
87
88////////////////////////////////////////////////////////////////////////////////
89/// method used to counter number of headers or returns name of specified header
90
92{
93 Int_t curr(0), cnt(0);
94
95 while (curr < buf.Length() - 2) {
96
97 Int_t next = buf.Index("\r\n", curr);
98 if (next == kNPOS)
99 break; // should never happen
100
101 if (cnt == number) {
102 // we should extract name of header
103 Int_t separ = curr + 1;
104 while ((separ < next) && (buf[separ] != ':'))
105 separ++;
106 return buf(curr, separ - curr);
107 }
108
109 curr = next + 2;
110 cnt++;
111 }
112
113 // return total number of headers
114 if (number == -1111)
115 return TString::Format("%d", cnt);
116 return TString();
117}
118
119
120////////////////////////////////////////////////////////////////////////////////
121/// Set content as text.
122/// Content will be copied by THttpCallArg
123void THttpCallArg::SetContent(const char *cont)
124{
125 if (cont)
126 fContent = cont;
127 else
128 fContent.clear();
129}
130
131////////////////////////////////////////////////////////////////////////////////
132/// Set text or binary content directly
133/// After method call argument cont will be in undefined state
134
135void THttpCallArg::SetContent(std::string &&cont)
136{
137 fContent = cont;
138}
139
140////////////////////////////////////////////////////////////////////////////////
141/// Set content type as "text/plain"
142
144{
145 SetContentType("text/plain");
146}
147
148////////////////////////////////////////////////////////////////////////////////
149/// Set content type as "text/plain" and also assigns content
150/// After method call argument \param txt will be in undefined state
151
152void THttpCallArg::SetTextContent(std::string &&txt)
153{
154 SetText();
155 fContent = txt;
156}
157
158////////////////////////////////////////////////////////////////////////////////
159/// Set content type as "text/xml"
160
162{
163 SetContentType("text/xml");
164}
165
166////////////////////////////////////////////////////////////////////////////////
167/// Set content type as "text/xml" and also assigns content
168/// After method call argument \param xml will be in undefined state
169
170void THttpCallArg::SetXmlContent(std::string &&xml)
171{
172 SetXml();
173 fContent = xml;
174}
175
176////////////////////////////////////////////////////////////////////////////////
177/// Set content type as "application/json"
178
180{
181 SetContentType("application/json");
182}
183
184////////////////////////////////////////////////////////////////////////////////
185/// Set content type as "application/json" and also assigns content
186/// After method call argument \param json will be in undefined state
187
189{
190 SetJson();
191 fContent = json;
192}
193
194////////////////////////////////////////////////////////////////////////////////
195/// Set content type as "application/x-binary"
196
198{
199 SetContentType("application/x-binary");
200}
201
202////////////////////////////////////////////////////////////////////////////////
203/// Set content type as "application/x-binary" and also assigns content
204/// After method call argument \param bin will be in undefined state
205
206void THttpCallArg::SetBinaryContent(std::string &&bin)
207{
208 SetBinary();
209 fContent = bin;
210}
211
212////////////////////////////////////////////////////////////////////////////////
213/// \deprecated Use signature with std::string
214/// Set data, posted with the request
215/// If make_copy==kFALSE, data will be released with free(data) call
216
217void THttpCallArg::SetPostData(void *data, Long_t length, Bool_t make_copy)
218{
219 fPostData.resize(length);
220
221 if (data && length) {
222 std::copy((const char *)data, (const char *)data + length, fPostData.begin());
223 if (!make_copy) free(data); // it supposed to get ownership over the buffer
224 }
225}
226
227////////////////////////////////////////////////////////////////////////////////
228/// set data, which is posted with the request
229/// Although std::string is used, not only text data can be assigned -
230/// std::string can contain any sequence of symbols
231
233{
234 fPostData = data;
235}
236
237////////////////////////////////////////////////////////////////////////////////
238/// Assign websocket identifier from the engine
239
241{
242 SetWSId(fWSEngine->GetId());
243}
244
245////////////////////////////////////////////////////////////////////////////////
246/// takeout websocket handle with HTTP call
247/// can be done only once
248
249std::shared_ptr<THttpWSEngine> THttpCallArg::TakeWSEngine()
250{
251 auto res = fWSEngine;
252 fWSEngine.reset();
253 return res;
254}
255
256////////////////////////////////////////////////////////////////////////////////
257/// Replace all occurrences of \param from by \param to in content
258/// Used only internally
259
260void THttpCallArg::ReplaceAllinContent(const std::string &from, const std::string &to)
261{
262 std::size_t start_pos = 0;
263 while((start_pos = fContent.find(from, start_pos)) != std::string::npos) {
264 fContent.replace(start_pos, from.length(), to);
265 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
266 }
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// \deprecated use SetContent(std::string &&arg) signature instead
271/// set binary data, which will be returned as reply body
272/// Memory should be allocated with std::malloc().
273/// THttpCallArg take over ownership over specified memory.
274/// Memory will be released by calling std::free() function.
275
276void THttpCallArg::SetBinData(void *data, Long_t length)
277{
278 // string content must be cleared in any case
279 if (length <= 0) {
280 fContent.clear();
281 } else {
282 fContent.resize(length);
283 if (data) {
284 std::copy((const char *)data, (const char *)data + length, fContent.begin());
285 free(data);
286 }
287 }
288}
289
290////////////////////////////////////////////////////////////////////////////////
291/// set complete path of requested http element
292/// For instance, it could be "/folder/subfolder/get.bin"
293/// Here "/folder/subfolder/" is element path and "get.bin" requested file.
294/// One could set path and file name separately
295
296void THttpCallArg::SetPathAndFileName(const char *fullpath)
297{
300
301 if (fullpath == 0)
302 return;
303
304 const char *rslash = strrchr(fullpath, '/');
305 if (rslash == 0) {
306 fFileName = fullpath;
307 } else {
308 while ((fullpath != rslash) && (*fullpath == '/'))
309 fullpath++;
310 fPathName.Append(fullpath, rslash - fullpath);
311 if (fPathName == "/")
313 fFileName = rslash + 1;
314 }
315}
316
317////////////////////////////////////////////////////////////////////////////////
318/// return specified header
319
321{
322 if ((name == 0) || (*name == 0))
323 return TString();
324
325 if (strcmp(name, "Content-Type") == 0)
326 return fContentType;
327 if (strcmp(name, "Content-Length") == 0)
328 return TString::Format("%ld", GetContentLength());
329
330 return AccessHeader(fHeader, name);
331}
332
333////////////////////////////////////////////////////////////////////////////////
334/// Set name: value pair to reply header
335/// Content-Type field handled separately - one should use SetContentType() method
336/// Content-Length field cannot be set at all;
337
338void THttpCallArg::AddHeader(const char *name, const char *value)
339{
340 if ((name == 0) || (*name == 0) || (strcmp(name, "Content-Length") == 0))
341 return;
342
343 if (strcmp(name, "Content-Type") == 0)
344 SetContentType(value);
345 else
346 AccessHeader(fHeader, name, value, kTRUE);
347}
348
349////////////////////////////////////////////////////////////////////////////////
350/// Set CacheControl http header to disable browser caching
351
353{
354 AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
355}
356
357////////////////////////////////////////////////////////////////////////////////
358/// Fills HTTP header, which can be send at the beggining of reply on the http request
359/// \param name is HTTP protocol name (default "HTTP/1.1")
360
361std::string THttpCallArg::FillHttpHeader(const char *name)
362{
363 std::string hdr(name ? name : "HTTP/1.1");
364
365 if ((fContentType.Length() == 0) || Is404())
366 hdr.append(" 404 Not Found\r\n"
367 "Content-Length: 0\r\n"
368 "Connection: close\r\n\r\n");
369 else
370 hdr.append(Form(" 200 OK\r\n"
371 "Content-Type: %s\r\n"
372 "Connection: keep-alive\r\n"
373 "Content-Length: %ld\r\n"
374 "%s\r\n",
375 GetContentType(), GetContentLength(), fHeader.Data()));
376
377 return hdr;
378}
379
380////////////////////////////////////////////////////////////////////////////////
381/// \depricated use FillHttpHeader with other signature
382/// Fills HTTP header, which can be send at the beggining of reply on the http request
383/// \param name is HTTP protocol name (default "HTTP/1.1")
384
385void THttpCallArg::FillHttpHeader(TString &hdr, const char *name)
386{
387 hdr = FillHttpHeader(name).c_str();
388}
389
390////////////////////////////////////////////////////////////////////////////////
391/// compress reply data with gzip compression
392
394{
395 char *objbuf = (char *)GetContent();
396 Long_t objlen = GetContentLength();
397
398 unsigned long objcrc = R__crc32(0, NULL, 0);
399 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
400
401 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
402 Int_t buflen = 10 + objlen + 8;
403 if (buflen < 512)
404 buflen = 512;
405
406 std::string buffer;
407 buffer.resize(buflen);
408
409 char *bufcur = (char *)buffer.data();
410
411 *bufcur++ = 0x1f; // first byte of ZIP identifier
412 *bufcur++ = 0x8b; // second byte of ZIP identifier
413 *bufcur++ = 0x08; // compression method
414 *bufcur++ = 0x00; // FLAG - empty, no any file names
415 *bufcur++ = 0; // empty timestamp
416 *bufcur++ = 0; //
417 *bufcur++ = 0; //
418 *bufcur++ = 0; //
419 *bufcur++ = 0; // XFL (eXtra FLags)
420 *bufcur++ = 3; // OS 3 means Unix
421 // strcpy(bufcur, "item.json");
422 // bufcur += strlen("item.json")+1;
423
424 char dummy[8];
425 memcpy(dummy, bufcur - 6, 6);
426
427 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
428 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, objbuf, objlen);
429
430 memcpy(bufcur - 6, dummy, 6);
431
432 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
433
434 // write CRC32
435 *bufcur++ = objcrc & 0xff;
436 *bufcur++ = (objcrc >> 8) & 0xff;
437 *bufcur++ = (objcrc >> 16) & 0xff;
438 *bufcur++ = (objcrc >> 24) & 0xff;
439
440 // write original data length
441 *bufcur++ = objlen & 0xff;
442 *bufcur++ = (objlen >> 8) & 0xff;
443 *bufcur++ = (objlen >> 16) & 0xff;
444 *bufcur++ = (objlen >> 24) & 0xff;
445
446 buffer.resize(bufcur - (char *)buffer.data());
447
448 SetContent(std::move(buffer));
449
450 SetEncoding("gzip");
451
452 return kTRUE;
453}
454
455////////////////////////////////////////////////////////////////////////////////
456/// method used to notify condition which waiting when operation will complete
457/// Condition notified only if not-postponed state is set
458
459void THttpCallArg::NotifyCondition()
460{
461 if (!fNotifyFlag && !IsPostponed()) {
463 HttpReplied();
464 }
465}
466
467////////////////////////////////////////////////////////////////////////////////
468/// virtual method to inform object that http request is processed
469/// Normally condition is notified and waiting thread will be awaked
470/// One could reimplement this method in sub-class
471
472void THttpCallArg::HttpReplied()
473{
474 fCond.notify_one();
475}
static RooMathCoreReg dummy
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
int Int_t
Definition: RtypesCore.h:41
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:363
char * Form(const char *fmt,...)
#define free
Definition: civetweb.c:1539
std::string fPostData
!< content - text or binary
Definition: THttpCallArg.h:67
Bool_t fNotifyFlag
! indicate that notification called
Definition: THttpCallArg.h:57
Bool_t CompressWithGzip()
compress reply data with gzip compression
void SetJson()
Set content type as "application/json".
TString GetHeader(const char *name)
return specified header
std::condition_variable fCond
! condition used to wait for processing
Definition: THttpCallArg.h:50
void SetPostData(void *data, Long_t length, Bool_t make_copy=kFALSE)
std::shared_ptr< THttpWSEngine > TakeWSEngine()
takeout websocket handle with HTTP call can be done only once
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
void SetText()
Set content type as "text/plain".
void SetTextContent(std::string &&txt)
Set content type as "text/plain" and also assigns content After method call argument.
TString fPathName
! item path
Definition: THttpCallArg.h:43
std::shared_ptr< THttpWSEngine > fWSEngine
! web-socket engine, which supplied to run created web socket
Definition: THttpCallArg.h:64
void SetPathAndFileName(const char *fullpath)
set complete path of requested http element For instance, it could be "/folder/subfolder/get....
TString fContentType
! type of content
Definition: THttpCallArg.h:52
void ReplaceAllinContent(const std::string &from, const std::string &to)
Replace all occurrences of.
virtual ~THttpCallArg()
destructor
TString CountHeader(const TString &buf, Int_t number=-1111) const
method used to counter number of headers or returns name of specified header
void SetBinary()
Set content type as "application/x-binary".
void AddNoCacheHeader()
Set CacheControl http header to disable browser caching.
TString AccessHeader(TString &buf, const char *name, const char *value=nullptr, Bool_t doing_set=kFALSE)
method used to get or set http header in the string buffer Header has following format: field1 : valu...
void SetXml()
Set content type as "text/xml".
void SetContent(const char *cont)
Set content as text.
void SetWSId(UInt_t id)
set web-socket id
Definition: THttpCallArg.h:105
TString fFileName
! file name
Definition: THttpCallArg.h:44
std::string fContent
Definition: THttpCallArg.h:66
void SetBinaryContent(std::string &&bin)
Set content type as "application/x-binary" and also assigns content After method call argument.
void SetContentType(const char *typ)
set content type like "text/xml" or "application/json"
Definition: THttpCallArg.h:159
void SetEncoding(const char *typ)
Set Content-Encoding header like gzip.
Definition: THttpCallArg.h:200
void SetJsonContent(std::string &&json)
Set content type as "application/json" and also assigns content After method call argument.
void AssignWSId()
Assign websocket identifier from the engine.
void SetXmlContent(std::string &&xml)
Set content type as "text/xml" and also assigns content After method call argument.
TString fHeader
! response header like ContentEncoding, Cache-Control and so on
Definition: THttpCallArg.h:54
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:644
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1151
const char * Data() const
Definition: TString.h:364
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
TString & Append(const char *cs)
Definition: TString.h:559
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:2286
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
basic_json<> json
default JSON class
Definition: json.hpp:12912
const char * cnt
Definition: TXMLSetup.cxx:74