Logo ROOT   6.18/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
32void 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
127Bool_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)
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
178void *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}
int Int_t
Definition: RtypesCore.h:41
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
void FCGX_ROOT_send_file(FCGX_Request *request, const char *fname)
Definition: TFastCgi.cxx:32
typedef void((*Func_t)())
TFastCgi()
normal constructor
Definition: TFastCgi.cxx:96
TString fTopName
! name of top item
Definition: TFastCgi.h:23
virtual Bool_t Create(const char *args)
initializes fastcgi variables and start thread, which will process incoming http requests
Definition: TFastCgi.cxx:127
Bool_t fDebugMode
! debug mode, may required for fastcgi debugging in other servers
Definition: TFastCgi.h:22
static void * run_func(void *)
Definition: TFastCgi.cxx:178
Int_t GetSocket() const
Definition: TFastCgi.h:33
virtual ~TFastCgi()
destructor
Definition: TFastCgi.cxx:105
Int_t fSocket
! socket used by fastcgi
Definition: TFastCgi.h:21
Bool_t fTerminating
! set when http server wants to terminate all engines
Definition: TFastCgi.h:25
TThread * fThrd
! thread which takes requests, can be many later
Definition: TFastCgi.h:24
THttpServer * GetServer() const
Returns pointer to THttpServer associated with engine.
Definition: THttpEngine.h:40
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
Bool_t ExecuteHttp(std::shared_ptr< THttpCallArg > arg)
Execute HTTP request.
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
const char * Data() const
Definition: TString.h:364
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:2311
Int_t Kill()
Kill this thread.
Definition: TThread.cxx:585
Int_t Run(void *arg=0)
Start the thread.
Definition: TThread.cxx:561
This class represents a WWW compatible URL.
Definition: TUrl.h:35
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition: TUrl.cxx:646
Bool_t IsValid() const
Definition: TUrl.h:82
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:615
const Int_t n
Definition: legend1.C:16