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