Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 <cstring>
15
16#include "RZip.h"
17#include "THttpWSEngine.h"
18
19/** \class THttpCallArg
20\ingroup http
21
22Contains arguments for single HTTP call
23
24Must be used in THttpEngine to process incoming http requests
25*/
26
27
29
30////////////////////////////////////////////////////////////////////////////////
31/// destructor
32
34{
35}
36
37////////////////////////////////////////////////////////////////////////////////
38/// method used to get or set http header in the string buffer
39///
40/// Header has following format:
41///
42/// field1 : value1\\r\\n
43/// field2 : value2\\r\\n
44///
45/// Such format corresponds to header format in HTTP requests
46
47TString THttpCallArg::AccessHeader(TString &buf, const char *name, const char *value, Bool_t doing_set)
48{
49 if (name == 0)
50 return TString();
51
52 Int_t curr = 0;
53
54 while (curr < buf.Length() - 2) {
55
56 Int_t next = buf.Index("\r\n", curr);
57 if (next == kNPOS)
58 break; // should never happen
59
60 if (buf.Index(name, curr) != curr) {
61 curr = next + 2;
62 continue;
63 }
64
65 if ((value == 0) && doing_set) {
66 // special case - empty value means that field must be removed completely
67 buf.Remove(curr, next - curr + 2);
68 return TString();
69 }
70
71 curr += strlen(name);
72 while ((curr < next) && (buf[curr] != ':'))
73 curr++;
74 curr++;
75 while ((curr < next) && (buf[curr] == ' '))
76 curr++;
77
78 if (value == 0)
79 return buf(curr, next - curr);
80 buf.Remove(curr, next - curr);
81 buf.Insert(curr, value);
82 return TString(value);
83 }
84
85 if (value == 0)
86 return TString();
87
88 buf.Append(TString::Format("%s: %s\r\n", name, value));
89 return TString(value);
90}
91
92////////////////////////////////////////////////////////////////////////////////
93/// method used to counter number of headers or returns name of specified header
94
96{
97 Int_t curr = 0, cnt = 0;
98
99 while (curr < buf.Length() - 2) {
100
101 Int_t next = buf.Index("\r\n", curr);
102 if (next == kNPOS)
103 break; // should never happen
104
105 if (cnt == number) {
106 // we should extract name of header
107 Int_t separ = curr + 1;
108 while ((separ < next) && (buf[separ] != ':'))
109 separ++;
110 return buf(curr, separ - curr);
111 }
112
113 curr = next + 2;
114 cnt++;
115 }
116
117 // return total number of headers
118 if (number == -1111)
119 return TString::Format("%d", cnt);
120 return TString();
121}
122
123
124////////////////////////////////////////////////////////////////////////////////
125/// Set content as text.
126///
127/// Content will be copied by THttpCallArg
128
129void THttpCallArg::SetContent(const char *cont)
130{
131 if (cont)
132 fContent = cont;
133 else
134 fContent.clear();
135}
136
137////////////////////////////////////////////////////////////////////////////////
138/// Set text or binary content directly
139/// After method call argument cont will be in undefined state
140
141void THttpCallArg::SetContent(std::string &&cont)
142{
143 fContent = cont;
144}
145
146////////////////////////////////////////////////////////////////////////////////
147/// Set content type as "text/plain"
148
150{
151 SetContentType("text/plain");
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// Set content type as "text/plain" and also assigns content
156///
157/// @param txt will be in undefined state after method call
158
159void THttpCallArg::SetTextContent(std::string &&txt)
160{
161 SetText();
162 fContent = txt;
163}
164
165////////////////////////////////////////////////////////////////////////////////
166/// Set content type as "text/xml"
167
169{
170 SetContentType("text/xml");
171}
172
173////////////////////////////////////////////////////////////////////////////////
174/// Set content type as "text/xml" and also assigns content
175///
176/// @param xml will be in undefined state after method call
177
178void THttpCallArg::SetXmlContent(std::string &&xml)
179{
180 SetXml();
181 fContent = xml;
182}
183
184////////////////////////////////////////////////////////////////////////////////
185/// Set content type as "application/json"
186
188{
189 SetContentType("application/json");
190}
191
192////////////////////////////////////////////////////////////////////////////////
193/// Set content type as "application/json" and also assigns content
194///
195/// @param json will be in undefined state after method call
196
198{
199 SetJson();
200 fContent = json;
201}
202
203////////////////////////////////////////////////////////////////////////////////
204/// Set content type as "application/x-binary"
205
207{
208 SetContentType("application/x-binary");
209}
210
211////////////////////////////////////////////////////////////////////////////////
212/// Set content type as "application/x-binary" and also assigns content
213///
214/// @param bin will be in undefined state after method call
215
216void THttpCallArg::SetBinaryContent(std::string &&bin)
217{
218 SetBinary();
219 fContent = bin;
220}
221
222////////////////////////////////////////////////////////////////////////////////
223/// Set data, posted with the request
224///
225/// If make_copy==kFALSE, data will be released with free(data) call
226/// @deprecated Use signature with std::string
227
229{
230 fPostData.resize(length);
231
232 if (data && length) {
233 std::copy((const char *)data, (const char *)data + length, fPostData.begin());
234 if (!make_copy) free(data); // it supposed to get ownership over the buffer
235 }
236}
237
238////////////////////////////////////////////////////////////////////////////////
239/// Set data, which is posted with the request
240///
241/// Although std::string is used, not only text data can be assigned -
242/// std::string can contain any sequence of symbols
243
245{
246 fPostData = data;
247}
248
249////////////////////////////////////////////////////////////////////////////////
250/// Assign websocket identifier from the engine
251
253{
254 SetWSId(fWSEngine->GetId());
255}
256
257////////////////////////////////////////////////////////////////////////////////
258/// Takeout websocket handle with HTTP call
259///
260/// can be done only once
261
262std::shared_ptr<THttpWSEngine> THttpCallArg::TakeWSEngine()
263{
264 auto res = fWSEngine;
265 fWSEngine.reset();
266 return res;
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// Replace all occurrences of string in content
271///
272/// @param from that to replace
273/// @param to new content
274/// @param once set to true to stop after first occurrence is replaced
275
276/// Normally used only internally
277
278void THttpCallArg::ReplaceAllinContent(const std::string &from, const std::string &to, bool once)
279{
280 std::size_t start_pos = 0;
281 while((start_pos = fContent.find(from, start_pos)) != std::string::npos) {
282 fContent.replace(start_pos, from.length(), to);
283 if (once) return;
284 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
285 }
286}
287
288////////////////////////////////////////////////////////////////////////////////
289/// Set complete path of requested http element
290///
291/// For instance, it could be "/folder/subfolder/get.bin"
292/// Here "/folder/subfolder/" is element path and "get.bin" requested file.
293/// One could set path and file name separately
294
295void THttpCallArg::SetPathAndFileName(const char *fullpath)
296{
299
300 if (fullpath == 0)
301 return;
302
303 const char *rslash = strrchr(fullpath, '/');
304 if (rslash == 0) {
305 fFileName = fullpath;
306 } else {
307 while ((fullpath != rslash) && (*fullpath == '/'))
308 fullpath++;
309 fPathName.Append(fullpath, rslash - fullpath);
310 if (fPathName == "/")
312 fFileName = rslash + 1;
313 }
314}
315
316////////////////////////////////////////////////////////////////////////////////
317/// Return specified header
318
320{
321 if ((name == 0) || (*name == 0))
322 return TString();
323
324 if (strcmp(name, "Content-Type") == 0)
325 return fContentType;
326 if (strcmp(name, "Content-Length") == 0)
327 return TString::Format("%ld", GetContentLength());
328
329 return AccessHeader(fHeader, name);
330}
331
332////////////////////////////////////////////////////////////////////////////////
333/// Set `name: value` pair to reply header
334///
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)
345 else
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 beginning of reply on the http request
359///
360/// @param name is HTTP protocol name (default "HTTP/1.1")
361
362std::string THttpCallArg::FillHttpHeader(const char *name)
363{
364 std::string hdr(name ? name : "HTTP/1.1");
365
366 if ((fContentType.Length() == 0) || Is404())
367 hdr.append(" 404 Not Found\r\n"
368 "Content-Length: 0\r\n"
369 "Connection: close\r\n\r\n");
370 else
371 hdr.append(TString::Format(" 200 OK\r\n"
372 "Content-Type: %s\r\n"
373 "Connection: keep-alive\r\n"
374 "Content-Length: %ld\r\n"
375 "%s\r\n",
377 .Data());
378
379 return hdr;
380}
381
382////////////////////////////////////////////////////////////////////////////////
383/// Compress reply data with gzip compression
384
386{
387 char *objbuf = (char *)GetContent();
388 Long_t objlen = GetContentLength();
389
390 unsigned long objcrc = R__crc32(0, NULL, 0);
391 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
392
393 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
394 Int_t buflen = 10 + objlen + 8;
395 if (buflen < 512)
396 buflen = 512;
397
398 std::string buffer;
399 buffer.resize(buflen);
400
401 char *bufcur = (char *)buffer.data();
402
403 *bufcur++ = 0x1f; // first byte of ZIP identifier
404 *bufcur++ = 0x8b; // second byte of ZIP identifier
405 *bufcur++ = 0x08; // compression method
406 *bufcur++ = 0x00; // FLAG - empty, no any file names
407 *bufcur++ = 0; // empty timestamp
408 *bufcur++ = 0; //
409 *bufcur++ = 0; //
410 *bufcur++ = 0; //
411 *bufcur++ = 0; // XFL (eXtra FLags)
412 *bufcur++ = 3; // OS 3 means Unix
413 // strcpy(bufcur, "item.json");
414 // bufcur += strlen("item.json")+1;
415
416 char dummy[8];
417 memcpy(dummy, bufcur - 6, 6);
418
419 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
420 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, objbuf, objlen);
421
422 memcpy(bufcur - 6, dummy, 6);
423
424 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
425
426 // write CRC32
427 *bufcur++ = objcrc & 0xff;
428 *bufcur++ = (objcrc >> 8) & 0xff;
429 *bufcur++ = (objcrc >> 16) & 0xff;
430 *bufcur++ = (objcrc >> 24) & 0xff;
431
432 // write original data length
433 *bufcur++ = objlen & 0xff;
434 *bufcur++ = (objlen >> 8) & 0xff;
435 *bufcur++ = (objlen >> 16) & 0xff;
436 *bufcur++ = (objlen >> 24) & 0xff;
437
438 buffer.resize(bufcur - (char *)buffer.data());
439
440 SetContent(std::move(buffer));
441
442 SetEncoding("gzip");
443
444 return kTRUE;
445}
446
447////////////////////////////////////////////////////////////////////////////////
448/// Method used to notify condition which waiting when operation will complete
449///
450/// Condition notified only if not-postponed state is set
451
453{
454 if (!fNotifyFlag && !IsPostponed()) {
456 HttpReplied();
457 }
458}
459
460////////////////////////////////////////////////////////////////////////////////
461/// virtual method to inform object that http request is processed
462///
463/// Normally condition is notified and waiting thread will be awaked
464/// One could reimplement this method in sub-class
465
467{
468 fCond.notify_one();
469}
nlohmann::json json
long Long_t
Definition RtypesCore.h:54
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:124
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
#define ClassImp(name)
Definition Rtypes.h:377
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
#define free
Definition civetweb.c:1539
Contains arguments for single HTTP call.
std::string fPostData
! data received with post request - text - or binary
Bool_t fNotifyFlag
! indicate that notification called
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
void SetPostData(void *data, Long_t length, Bool_t make_copy=kFALSE)
Set data, posted with the request.
std::shared_ptr< THttpWSEngine > TakeWSEngine()
Takeout websocket handle with HTTP call.
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header.
void SetText()
Set content type as "text/plain".
void SetTextContent(std::string &&txt)
Set content type as "text/plain" and also assigns content.
virtual void HttpReplied()
virtual method to inform object that http request is processed
void ReplaceAllinContent(const std::string &from, const std::string &to, bool once=false)
Replace all occurrences of string in content.
TString fPathName
! item path
std::shared_ptr< THttpWSEngine > fWSEngine
! web-socket engine, which supplied to run created web socket
void NotifyCondition()
Method used to notify condition which waiting when operation will complete.
void SetPathAndFileName(const char *fullpath)
Set complete path of requested http element.
TString fContentType
! type of content
Long_t GetContentLength() const
Bool_t Is404() const
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
const void * GetContent() const
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
void SetXml()
Set content type as "text/xml".
void SetContent(const char *cont)
Set content as text.
Bool_t IsPostponed() const
void SetWSId(UInt_t id)
set web-socket id
TString fFileName
! file name
std::string fContent
! content - text or binary
void SetBinaryContent(std::string &&bin)
Set content type as "application/x-binary" and also assigns content.
void SetContentType(const char *typ)
set content type like "text/xml" or "application/json"
void SetEncoding(const char *typ)
Set Content-Encoding header like gzip.
void SetJsonContent(std::string &&json)
Set content type as "application/json" and also assigns content.
const char * GetContentType() const
void AssignWSId()
Assign websocket identifier from the engine.
void SetXmlContent(std::string &&xml)
Set content type as "text/xml" and also assigns content.
std::string FillHttpHeader(const char *header=nullptr)
Fills HTTP header, which can be send at the beginning of reply on the http request.
TString fHeader
! response header like ContentEncoding, Cache-Control and so on
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
TString & Insert(Ssiz_t pos, const char *s)
Definition TString.h:661
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1235
const char * Data() const
Definition TString.h:376
TString & Remove(Ssiz_t pos)
Definition TString.h:685
TString & Append(const char *cs)
Definition TString.h:572
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:2378
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651