Logo ROOT   6.10/09
Reference Guide
TFastCgi.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 28/12/2013
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 "TFastCgi.h"
13 
14 #include "TThread.h"
15 #include "TUrl.h"
16 #include "THttpServer.h"
17 
18 #include <string.h>
19 
20 #ifdef WIN32
21 #include <io.h>
22 #else
23 #include <unistd.h>
24 #endif
25 
26 #ifndef HTTP_WITHOUT_FASTCGI
27 
28 #include "fcgiapp.h"
29 
30 #include <stdlib.h>
31 
32 void FCGX_ROOT_send_file(FCGX_Request *request, const char *fname)
33 {
34  Int_t length = 0;
35 
36  char *buf = THttpServer::ReadFileContent(fname, length);
37 
38  if (buf == 0) {
39  FCGX_FPrintF(request->out,
40  "Status: 404 Not Found\r\n"
41  "Content-Length: 0\r\n" // Always set Content-Length
42  "Connection: close\r\n\r\n");
43  } else {
44 
45  FCGX_FPrintF(request->out,
46  "Status: 200 OK\r\n"
47  "Content-Type: %s\r\n"
48  "Content-Length: %d\r\n" // Always set Content-Length
49  "\r\n",
50  THttpServer::GetMimeType(fname), length);
51 
52  FCGX_PutStr(buf, length, request->out);
53 
54  free(buf);
55  }
56 }
57 
58 #endif
59 
60 //////////////////////////////////////////////////////////////////////////
61 // //
62 // TFastCgi //
63 // //
64 // http engine implementation, based on fastcgi package //
65 // Allows to redirect http requests from normal web server like //
66 // Apache or lighttpd //
67 // //
68 // Configuration example for lighttpd //
69 // //
70 // server.modules += ( "mod_fastcgi" ) //
71 // fastcgi.server = ( //
72 // "/remote_scripts/" => //
73 // (( "host" => "192.168.1.11", //
74 // "port" => 9000, //
75 // "check-local" => "disable", //
76 // "docroot" => "/" //
77 // )) //
78 // ) //
79 // //
80 // When creating THttpServer, one should specify: //
81 // //
82 // THttpServer* serv = new THttpServer("fastcgi:9000"); //
83 // //
84 // In this case, requests to lighttpd server will be //
85 // redirected to ROOT session. Like: //
86 // http://lighttpdhost/remote_scripts/root.cgi/ //
87 // //
88 // Following additional options can be specified //
89 // top=foldername - name of top folder, seen in the browser //
90 // debug=1 - run fastcgi server in debug mode //
91 // Example: //
92 // serv->CreateEngine("fastcgi:9000?top=fastcgiserver"); //
93 // //
94 // //
95 //////////////////////////////////////////////////////////////////////////
96 
98 
99  ////////////////////////////////////////////////////////////////////////////////
100  /// normal constructor
101 
103  : THttpEngine("fastcgi", "fastcgi interface to webserver"), fSocket(0), fDebugMode(kFALSE), fTopName(), fThrd(0)
104 {
105 }
106 
107 ////////////////////////////////////////////////////////////////////////////////
108 /// destructor
109 
111 {
112  if (fThrd) {
113  // running thread will be killed
114  fThrd->Kill();
115  delete fThrd;
116  fThrd = 0;
117  }
118 
119  if (fSocket > 0) {
120  // close opened socket
121  close(fSocket);
122  fSocket = 0;
123  }
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// initializes fastcgi variables and start thread,
128 /// which will process incoming http requests
129 
130 Bool_t TFastCgi::Create(const char *args)
131 {
132 #ifndef HTTP_WITHOUT_FASTCGI
133  FCGX_Init();
134 
135  TString sport = ":9000";
136 
137  if ((args != 0) && (strlen(args) > 0)) {
138 
139  // first extract port number
140  sport = ":";
141  while ((*args != 0) && (*args >= '0') && (*args <= '9')) sport.Append(*args++);
142 
143  // than search for extra parameters
144  while ((*args != 0) && (*args != '?')) args++;
145 
146  if (*args == '?') {
147  TUrl url(TString::Format("http://localhost/folder%s", args));
148 
149  if (url.IsValid()) {
150 
151  url.ParseOptions();
152 
153  if (url.GetValueFromOptions("debug") != 0) fDebugMode = kTRUE;
154 
155  const char *top = url.GetValueFromOptions("top");
156  if (top != 0) fTopName = top;
157  }
158  }
159  }
160 
161  Info("Create", "Starting FastCGI server on port %s", sport.Data() + 1);
162 
163  fSocket = FCGX_OpenSocket(sport.Data(), 10);
164  fThrd = new TThread("FastCgiThrd", TFastCgi::run_func, this);
165  fThrd->Run();
166 
167  return kTRUE;
168 #else
169  (void)args;
170  Error("Create", "ROOT compiled without fastcgi support");
171  return kFALSE;
172 #endif
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 
177 void *TFastCgi::run_func(void *args)
178 {
179 #ifndef HTTP_WITHOUT_FASTCGI
180 
181  TFastCgi *engine = (TFastCgi *)args;
182 
183  FCGX_Request request;
184 
185  FCGX_InitRequest(&request, engine->GetSocket(), 0);
186 
187  int count = 0;
188 
189  while (1) {
190 
191  int rc = FCGX_Accept_r(&request);
192 
193  if (rc != 0) continue;
194 
195  count++;
196 
197  const char *inp_path = FCGX_GetParam("PATH_INFO", request.envp);
198  const char *inp_query = FCGX_GetParam("QUERY_STRING", request.envp);
199  const char *inp_method = FCGX_GetParam("REQUEST_METHOD", request.envp);
200  const char *inp_length = FCGX_GetParam("CONTENT_LENGTH", request.envp);
201 
202  THttpCallArg arg;
203  if (inp_path != 0) arg.SetPathAndFileName(inp_path);
204  if (inp_query != 0) arg.SetQuery(inp_query);
205  if (inp_method != 0) arg.SetMethod(inp_method);
206  if (engine->fTopName.Length() > 0) arg.SetTopName(engine->fTopName.Data());
207  int len = 0;
208  if (inp_length != 0) len = strtol(inp_length, NULL, 10);
209  if (len > 0) {
210  void *buf = malloc(len + 1); // one myte more for null-termination
211  int nread = FCGX_GetStr((char *)buf, len, request.in);
212  if (nread > 0)
213  arg.SetPostData(buf, nread);
214  else
215  free(buf);
216  }
217 
218  TString header;
219  for (char **envp = request.envp; *envp != NULL; envp++) {
220  TString entry = *envp;
221  for (Int_t n = 0; n < entry.Length(); n++)
222  if (entry[n] == '=') {
223  entry[n] = ':';
224  break;
225  }
226  header.Append(entry);
227  header.Append("\r\n");
228  }
229  arg.SetRequestHeader(header);
230 
231  TString username = arg.GetRequestHeader("REMOTE_USER");
232  if ((username.Length() > 0) && (arg.GetRequestHeader("AUTH_TYPE").Length() > 0)) arg.SetUserName(username);
233 
234  if (engine->fDebugMode) {
235  FCGX_FPrintF(request.out, "Status: 200 OK\r\n"
236  "Content-type: text/html\r\n"
237  "\r\n"
238  "<title>FastCGI echo</title>"
239  "<h1>FastCGI echo</h1>\n");
240 
241  FCGX_FPrintF(request.out, "Request %d:<br/>\n<pre>\n", count);
242  FCGX_FPrintF(request.out, " Method : %s\n", arg.GetMethod());
243  FCGX_FPrintF(request.out, " PathName : %s\n", arg.GetPathName());
244  FCGX_FPrintF(request.out, " FileName : %s\n", arg.GetFileName());
245  FCGX_FPrintF(request.out, " Query : %s\n", arg.GetQuery());
246  FCGX_FPrintF(request.out, " PostData : %ld\n", arg.GetPostDataLength());
247  FCGX_FPrintF(request.out, "</pre><p>\n");
248 
249  FCGX_FPrintF(request.out, "Environment:<br/>\n<pre>\n");
250  for (char **envp = request.envp; *envp != NULL; envp++) {
251  FCGX_FPrintF(request.out, " %s\n", *envp);
252  }
253  FCGX_FPrintF(request.out, "</pre><p>\n");
254 
255  FCGX_Finish_r(&request);
256  continue;
257  }
258 
259  TString fname;
260 
261  if (engine->GetServer()->IsFileRequested(inp_path, fname)) {
262  FCGX_ROOT_send_file(&request, fname.Data());
263  FCGX_Finish_r(&request);
264  continue;
265  }
266 
267  TString hdr;
268 
269  if (!engine->GetServer()->ExecuteHttp(&arg) || arg.Is404()) {
270  arg.FillHttpHeader(hdr, "Status:");
271  FCGX_FPrintF(request.out, hdr.Data());
272  } else if (arg.IsFile()) {
273  FCGX_ROOT_send_file(&request, (const char *)arg.GetContent());
274  } else {
275 
276  // TODO: check in request header that gzip encoding is supported
277  if (arg.GetZipping() > 0) arg.CompressWithGzip();
278 
279  arg.FillHttpHeader(hdr, "Status:");
280  FCGX_FPrintF(request.out, hdr.Data());
281 
282  FCGX_PutStr((const char *)arg.GetContent(), (int)arg.GetContentLength(), request.out);
283  }
284 
285  FCGX_Finish_r(&request);
286 
287  } /* while */
288 
289  return 0;
290 
291 #else
292  return args;
293 #endif
294 }
const char * GetFileName() const
returns file name from request URL
Definition: THttpCallArg.h:130
virtual Bool_t Create(const char *args)
initializes fastcgi variables and start thread, which will process incoming http requests ...
Definition: TFastCgi.cxx:130
void SetRequestHeader(const char *h)
set full set of request header
Definition: THttpCallArg.h:100
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:847
TThread * fThrd
! thread which takes requests, can be many later
Definition: TFastCgi.h:24
This class represents a WWW compatible URL.
Definition: TUrl.h:35
Basic string class.
Definition: TString.h:129
const char * GetPathName() const
returns path name from request URL
Definition: THttpCallArg.h:127
void SetQuery(const char *q)
set request query
Definition: THttpCallArg.h:85
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
#define NULL
Definition: RtypesCore.h:88
#define malloc
Definition: civetweb.c:818
const char * GetQuery() const
returns request query (string after ? in request URL)
Definition: THttpCallArg.h:136
Bool_t IsValid() const
Definition: TUrl.h:82
void SetUserName(const char *n)
set name of authenticated user
Definition: THttpCallArg.h:82
Int_t fSocket
! socket used by fastcgi
Definition: TFastCgi.h:21
void FCGX_ROOT_send_file(FCGX_Request *request, const char *fname)
Definition: TFastCgi.cxx:32
THttpServer * GetServer() const
Returns pointer to THttpServer associated with engine.
Definition: THttpEngine.h:41
void SetTopName(const char *topname)
set engine-specific top-name
Definition: THttpCallArg.h:71
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:2345
void SetPostData(void *data, Long_t length)
set data, posted with the request buffer should be allocated with malloc(length+1) call...
TString fTopName
! name of top item
Definition: TFastCgi.h:23
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 & Append(const char *cs)
Definition: TString.h:497
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition: TUrl.cxx:649
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:873
Ssiz_t Length() const
Definition: TString.h:388
Int_t Kill()
Kill this thread.
Definition: TThread.cxx:576
Bool_t ExecuteHttp(THttpCallArg *arg)
Execute HTTP request.
const Bool_t kFALSE
Definition: RtypesCore.h:92
const void * GetContent() const
Definition: THttpCallArg.h:208
#define ClassImp(name)
Definition: Rtypes.h:336
void SetMethod(const char *method)
set request method kind like GET or POST
Definition: THttpCallArg.h:68
#define free
Definition: civetweb.c:821
Bool_t fDebugMode
! debug mode, may required for fastcgi debugging in other servers
Definition: TFastCgi.h:22
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:618
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
typedef void((*Func_t)())
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
Bool_t IsFile() const
Definition: THttpCallArg.h:200
Bool_t Is404() const
Definition: THttpCallArg.h:199
virtual ~TFastCgi()
destructor
Definition: TFastCgi.cxx:110
Int_t GetSocket() const
Definition: TFastCgi.h:29
Int_t GetZipping() const
return kind of content zipping
Definition: THttpCallArg.h:188
static void * run_func(void *)
Definition: TFastCgi.cxx:177
TString GetRequestHeader(const char *name)
get named field from request header
Definition: THttpCallArg.h:109
Long_t GetPostDataLength() const
return length of posted with request data
Definition: THttpCallArg.h:124
const Bool_t kTRUE
Definition: RtypesCore.h:91
const Int_t n
Definition: legend1.C:16
const char * GetMethod() const
returns request method like GET or POST
Definition: THttpCallArg.h:115
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
Bool_t CompressWithGzip()
compress reply data with gzip compression
void FillHttpHeader(TString &buf, const char *header=0)
fill HTTP header
const char * Data() const
Definition: TString.h:347
Long_t GetContentLength() const
Definition: THttpCallArg.h:206