ROOT  6.06/09
Reference Guide
TCivetweb.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 21/12/2013
3 
4 #include "TCivetweb.h"
5 
6 #include "../civetweb/civetweb.h"
7 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "THttpServer.h"
12 #include "TUrl.h"
13 
14 static int log_message_handler(const struct mg_connection *conn, const char *message)
15 {
16  const struct mg_context *ctx = mg_get_context(conn);
17 
18  TCivetweb* engine = (TCivetweb*) mg_get_user_data(ctx);
19 
20  if (engine) return engine->ProcessLog(message);
21 
22  // provide debug output
23  if ((gDebug>0) || (strstr(message,"cannot bind to")!=0))
24  fprintf(stderr, "Error in <TCivetweb::Log> %s\n",message);
25 
26  return 0;
27 }
28 
29 
30 static int begin_request_handler(struct mg_connection *conn)
31 {
32  TCivetweb *engine = (TCivetweb *) mg_get_request_info(conn)->user_data;
33  if (engine == 0) return 0;
34  THttpServer *serv = engine->GetServer();
35  if (serv == 0) return 0;
36 
37  const struct mg_request_info *request_info = mg_get_request_info(conn);
38 
39  THttpCallArg arg;
40 
42 
43  Bool_t execres = kTRUE, debug = engine->IsDebugMode();
44 
45  if (!debug && serv->IsFileRequested(request_info->uri, filename)) {
46  if ((filename.Index(".js") != kNPOS) || (filename.Index(".css") != kNPOS)) {
47  Int_t length = 0;
48  char *buf = THttpServer::ReadFileContent(filename.Data(), length);
49  if (buf == 0) {
50  arg.Set404();
51  } else {
53  arg.SetBinData(buf, length);
54  arg.AddHeader("Cache-Control", "max-age=3600");
55  arg.SetZipping(2);
56  }
57  } else {
58  arg.SetFile(filename.Data());
59  }
60  } else {
61  arg.SetPathAndFileName(request_info->uri); // path and file name
62  arg.SetQuery(request_info->query_string); // query arguments
63  arg.SetTopName(engine->GetTopName());
64  arg.SetMethod(request_info->request_method); // method like GET or POST
65  if (request_info->remote_user!=0)
66  arg.SetUserName(request_info->remote_user);
67 
68  TString header;
69  for (int n = 0; n < request_info->num_headers; n++)
70  header.Append(TString::Format("%s: %s\r\n", request_info->http_headers[n].name, request_info->http_headers[n].value));
71  arg.SetRequestHeader(header);
72 
73  const char* len = mg_get_header(conn, "Content-Length");
74  Int_t ilen = len!=0 ? TString(len).Atoi() : 0;
75 
76  if (ilen>0) {
77  void* buf = malloc(ilen+1); // one byte more for null-termination
78  Int_t iread = mg_read(conn, buf, ilen);
79  if (iread==ilen) arg.SetPostData(buf, ilen);
80  else free(buf);
81  }
82 
83  if (debug) {
84  TString cont;
85  cont.Append("<title>Civetweb echo</title>");
86  cont.Append("<h1>Civetweb echo</h1>\n");
87 
88  static int count = 0;
89 
90  cont.Append(TString::Format("Request %d:<br/>\n<pre>\n", ++count));
91  cont.Append(TString::Format(" Method : %s\n", arg.GetMethod()));
92  cont.Append(TString::Format(" PathName : %s\n", arg.GetPathName()));
93  cont.Append(TString::Format(" FileName : %s\n", arg.GetFileName()));
94  cont.Append(TString::Format(" Query : %s\n", arg.GetQuery()));
95  cont.Append(TString::Format(" PostData : %ld\n", arg.GetPostDataLength()));
96  if (arg.GetUserName())
97  cont.Append(TString::Format(" User : %s\n", arg.GetUserName()));
98 
99  cont.Append("</pre><p>\n");
100 
101  cont.Append("Environment:<br/>\n<pre>\n");
102  for (int n = 0; n < request_info->num_headers; n++)
103  cont.Append(TString::Format(" %s = %s\n", request_info->http_headers[n].name, request_info->http_headers[n].value));
104  cont.Append("</pre><p>\n");
105 
106  arg.SetContentType("text/html");
107 
108  arg.SetContent(cont);
109 
110  } else {
111  execres = serv->ExecuteHttp(&arg);
112  }
113  }
114 
115  if (!execres || arg.Is404()) {
116  TString hdr;
117  arg.FillHttpHeader(hdr, "HTTP/1.1");
118  mg_printf(conn, "%s", hdr.Data());
119  } else if (arg.IsFile()) {
120  mg_send_file(conn, (const char *) arg.GetContent());
121  } else {
122 
123  Bool_t dozip = arg.GetZipping() > 0;
124  switch (arg.GetZipping()) {
125  case 2:
126  if (arg.GetContentLength() < 10000) {
127  dozip = kFALSE;
128  break;
129  }
130  case 1:
131  // check if request header has Accept-Encoding
132  dozip = kFALSE;
133  for (int n = 0; n < request_info->num_headers; n++) {
134  TString name = request_info->http_headers[n].name;
135  if (name.Index("Accept-Encoding", 0, TString::kIgnoreCase) != 0) continue;
136  TString value = request_info->http_headers[n].value;
137  dozip = (value.Index("gzip", 0, TString::kIgnoreCase) != kNPOS);
138  break;
139  }
140 
141  break;
142  case 3:
143  dozip = kTRUE;
144  break;
145  }
146 
147  if (dozip) arg.CompressWithGzip();
148 
149  TString hdr;
150  arg.FillHttpHeader(hdr, "HTTP/1.1");
151  mg_printf(conn, "%s", hdr.Data());
152 
153  if (arg.GetContentLength() > 0)
154  mg_write(conn, arg.GetContent(), (size_t) arg.GetContentLength());
155  }
156 
157  // Returning non-zero tells civetweb that our function has replied to
158  // the client, and civetweb should not send client any more data.
159  return 1;
160 }
161 
162 
163 //////////////////////////////////////////////////////////////////////////
164 // //
165 // TCivetweb //
166 // //
167 // http server implementation, based on civetweb embedded server //
168 // It is default kind of engine, created for THttpServer //
169 // //
170 // Following additional options can be specified //
171 // top=foldername - name of top folder, seen in the browser //
172 // thrds=N - use N threads to run civetweb server (default 5) //
173 // auth_file - global authentication file //
174 // auth_domain - domain name, used for authentication //
175 // //
176 // Example: //
177 // new THttpServer("http:8080?top=MyApp&thrds=3"); //
178 // //
179 // Authentication: //
180 // When auth_file and auth_domain parameters are specified, access //
181 // to running http server will be possible only after user //
182 // authentication, using so-call digest method. To generate //
183 // authentication file, htdigest routine should be used: //
184 // //
185 // [shell] htdigest -c .htdigest domain_name user //
186 // //
187 // When creating server, parameters should be: //
188 // //
189 // new THttpServer("http:8080?auth_file=.htdigets&auth_domain=domain_name"); //
190 // //
191 //////////////////////////////////////////////////////////////////////////
192 
193 
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// constructor
198 
199 TCivetweb::TCivetweb() :
200  THttpEngine("civetweb", "compact embedded http server"),
201  fCtx(0),
202  fCallbacks(0),
203  fTopName(),
204  fDebug(kFALSE)
205 {
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// destructor
210 
212 {
213  if (fCtx != 0) mg_stop((struct mg_context *) fCtx);
214  if (fCallbacks != 0) free(fCallbacks);
215  fCtx = 0;
216  fCallbacks = 0;
217 }
218 
219 ////////////////////////////////////////////////////////////////////////////////
220 /// process civetweb log message, can be used to detect critical errors
221 
223 {
224  if ((gDebug>0) || (strstr(message,"cannot bind to")!=0)) Error("Log", "%s", message);
225 
226  return 0;
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 /// Creates embedded civetweb server
231 /// As main argument, http port should be specified like "8090".
232 /// Or one can provide combination of ipaddress and portnumber like 127.0.0.1:8090
233 /// Extra parameters like in URL string could be specified after '?' mark:
234 /// thrds=N - there N is number of threads used by the civetweb (default is 5)
235 /// top=name - configure top name, visible in the web browser
236 /// auth_file=filename - authentication file name, created with htdigets utility
237 /// auth_domain=domain - authentication domain
238 /// loopback - bind specified port to loopback 127.0.0.1 address
239 /// debug - enable debug mode, server always returns html page with request info
240 
241 Bool_t TCivetweb::Create(const char *args)
242 {
243  fCallbacks = malloc(sizeof(struct mg_callbacks));
244  memset(fCallbacks, 0, sizeof(struct mg_callbacks));
245  ((struct mg_callbacks *) fCallbacks)->begin_request = begin_request_handler;
246  ((struct mg_callbacks *) fCallbacks)->log_message = log_message_handler;
247  TString sport = "8080";
248  TString num_threads = "5";
249  TString auth_file, auth_domain, log_file;
250 
251  // extract arguments
252  if ((args != 0) && (strlen(args) > 0)) {
253 
254  // first extract port number
255  sport = "";
256  while ((*args != 0) && (*args != '?') && (*args != '/'))
257  sport.Append(*args++);
258 
259  // than search for extra parameters
260  while ((*args != 0) && (*args != '?')) args++;
261 
262  if (*args == '?') {
263  TUrl url(TString::Format("http://localhost/folder%s", args));
264 
265  if (url.IsValid()) {
266  url.ParseOptions();
267 
268  const char *top = url.GetValueFromOptions("top");
269  if (top != 0) fTopName = top;
270 
271  const char *log = url.GetValueFromOptions("log");
272  if (log != 0) log_file = log;
273 
274  Int_t thrds = url.GetIntValueFromOptions("thrds");
275  if (thrds > 0) num_threads.Form("%d", thrds);
276 
277  const char *afile = url.GetValueFromOptions("auth_file");
278  if (afile != 0) auth_file = afile;
279 
280  const char *adomain = url.GetValueFromOptions("auth_domain");
281  if (adomain != 0) auth_domain = adomain;
282 
283  if (url.HasOption("debug")) fDebug = kTRUE;
284 
285  if (url.HasOption("loopback") && (sport.Index(":")==kNPOS))
286  sport = TString("127.0.0.1:") + sport;
287  }
288  }
289  }
290 
291  const char *options[20];
292  int op(0);
293 
294  Info("Create", "Starting HTTP server on port %s", sport.Data());
295 
296  options[op++] = "listening_ports";
297  options[op++] = sport.Data();
298  options[op++] = "num_threads";
299  options[op++] = num_threads.Data();
300 
301  if ((auth_file.Length() > 0) && (auth_domain.Length() > 0)) {
302  options[op++] = "global_auth_file";
303  options[op++] = auth_file.Data();
304  options[op++] = "authentication_domain";
305  options[op++] = auth_domain.Data();
306  }
307 
308  if (log_file.Length() > 0) {
309  options[op++] = "error_log_file";
310  options[op++] = log_file.Data();
311  }
312 
313  options[op++] = 0;
314 
315  // Start the web server.
316  fCtx = mg_start((struct mg_callbacks *) fCallbacks, this, options);
317 
318  return fCtx != 0;
319 }
320 
void SetZipping(Int_t kind)
Definition: THttpCallArg.h:273
const char * remote_user
Definition: civetweb.h:47
THttpServer * GetServer() const
Definition: THttpEngine.h:38
void SetRequestHeader(const char *h)
Definition: THttpCallArg.h:110
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
Definition: TUrl.cxx:670
static int begin_request_handler(struct mg_connection *conn)
Definition: TCivetweb.cxx:30
TString fTopName
call-back table for civetweb webserver
Definition: TCivetweb.h:15
const char * uri
Definition: civetweb.h:43
Ssiz_t Length() const
Definition: TString.h:390
This class represents a WWW compatible URL.
Definition: TUrl.h:41
int mg_read(struct mg_connection *conn, void *buf, size_t len)
Definition: civetweb.c:1996
Long_t GetContentLength() const
Definition: THttpCallArg.h:323
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:892
Bool_t Is404() const
Definition: THttpCallArg.h:306
static const char * filename()
void mg_stop(struct mg_context *ctx)
Definition: civetweb.c:6341
const struct mg_context * mg_get_context(const struct mg_connection *conn)
Definition: civetweb.c:696
const char * GetPathName() const
Definition: THttpCallArg.h:173
Basic string class.
Definition: TString.h:137
virtual Bool_t Create(const char *args)
Creates embedded civetweb server As main argument, http port should be specified like "8090"...
Definition: TCivetweb.cxx:241
void SetQuery(const char *q)
Definition: THttpCallArg.h:101
int Int_t
Definition: RtypesCore.h:41
struct mg_request_info::mg_header http_headers[64]
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
size_t
Definition: TBuffer.cxx:28
Bool_t fDebug
name of top item
Definition: TCivetweb.h:16
void SetContentType(const char *typ)
Definition: THttpCallArg.h:203
const void * GetContent() const
Definition: THttpCallArg.h:328
void SetUserName(const char *n)
Definition: THttpCallArg.h:94
void * fCallbacks
civetweb context
Definition: TCivetweb.h:14
void SetContent(const char *c)
Definition: THttpCallArg.h:264
const char * GetMethod() const
Definition: THttpCallArg.h:145
void SetTopName(const char *topname)
Definition: THttpCallArg.h:71
const char * Data() const
Definition: TString.h:349
const char * request_method
Definition: civetweb.h:42
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:2334
Vc_ALWAYS_INLINE void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:94
void SetPostData(void *data, Long_t length)
set data, posted with the request buffer should be allocated with malloc(length+1) call...
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.
virtual ~TCivetweb()
destructor
Definition: TCivetweb.cxx:211
Bool_t IsFile() const
Definition: THttpCallArg.h:311
const char * GetTopName() const
Definition: TCivetweb.h:24
Int_t ProcessLog(const char *message)
process civetweb log message, can be used to detect critical errors
Definition: TCivetweb.cxx:222
TString & Append(const char *cs)
Definition: TString.h:492
Int_t GetIntValueFromOptions(const char *key) const
Return a value for a given key from the URL options as an Int_t, a missing key returns -1...
Definition: TUrl.cxx:659
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1964
void mg_send_file(struct mg_connection *conn, const char *path)
Definition: civetweb.c:3435
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
const char * GetQuery() const
Definition: THttpCallArg.h:194
Bool_t IsValid() const
Definition: TUrl.h:88
int mg_printf(struct mg_connection *conn, const char *fmt,...)
Definition: civetweb.c:2151
Bool_t IsDebugMode() const
Definition: TCivetweb.h:29
void SetBinData(void *data, Long_t length)
set binary data, which will be returned as reply body
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition: TUrl.cxx:647
Double_t length(const TVector2 &v)
Definition: CsgOps.cxx:347
const char * GetFileName() const
Definition: THttpCallArg.h:180
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2321
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
const char * GetUserName() const
Definition: THttpCallArg.h:187
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
Definition: civetweb.c:6357
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
Definition: civetweb.c:2037
Bool_t ExecuteHttp(THttpCallArg *arg)
Execute HTTP request.
const char * mg_get_header(const struct mg_connection *conn, const char *name)
Definition: civetweb.c:1033
static int log_message_handler(const struct mg_connection *conn, const char *message)
Definition: TCivetweb.cxx:14
void * mg_get_user_data(const struct mg_context *ctx)
Definition: civetweb.c:701
void SetMethod(const char *method)
Definition: THttpCallArg.h:64
Int_t GetZipping() const
Definition: THttpCallArg.h:284
void * user_data
Definition: civetweb.h:52
#define name(a, b)
Definition: linkTestLib0.cpp:5
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
const Ssiz_t kNPOS
Definition: Rtypes.h:115
void SetFile(const char *filename=0)
Definition: THttpCallArg.h:217
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:616
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
bool debug
struct mg_request_info * mg_get_request_info(struct mg_connection *conn)
Definition: civetweb.c:851
Long_t GetPostDataLength() const
Definition: THttpCallArg.h:166
const char * query_string
Definition: civetweb.h:45
string message
Definition: ROOT.py:94
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
ClassImp(TCivetweb) TCivetweb
constructor
Definition: TCivetweb.cxx:194
const Bool_t kTRUE
Definition: Rtypes.h:91
float value
Definition: math.cpp:443
Vc_ALWAYS_INLINE_L T *Vc_ALWAYS_INLINE_R malloc(size_t n)
Allocates memory on the Heap with alignment and padding suitable for vectorized access.
Definition: memory.h:67
const Int_t n
Definition: legend1.C:16
double log(double)
void * fCtx
Definition: TCivetweb.h:13
Bool_t CompressWithGzip()
compress reply data with gzip compression
void FillHttpHeader(TString &buf, const char *header=0)
fill HTTP header