#include "TFastCgi.h"
#include "TThread.h"
#include "TUrl.h"
#include "THttpServer.h"
#include <string.h>
#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#ifndef HTTP_WITHOUT_FASTCGI
#include "fcgiapp.h"
#include <stdlib.h>
void FCGX_ROOT_send_file(FCGX_Request *request, const char *fname)
{
Int_t length = 0;
char *buf = THttpServer::ReadFileContent(fname, length);
if (buf == 0) {
FCGX_FPrintF(request->out,
"Status: 404 Not Found\r\n"
"Content-Length: 0\r\n"
"Connection: close\r\n\r\n");
} else {
FCGX_FPrintF(request->out,
"Status: 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"\r\n", THttpServer::GetMimeType(fname), length);
FCGX_PutStr(buf, length, request->out);
free(buf);
}
}
#endif
TFastCgi::TFastCgi() :
THttpEngine("fastcgi", "fastcgi interface to webserver"),
fSocket(0),
fDebugMode(kFALSE),
fTopName(),
fThrd(0)
{
}
TFastCgi::~TFastCgi()
{
if (fThrd) {
fThrd->Kill();
delete fThrd;
fThrd = 0;
}
if (fSocket > 0) {
close(fSocket);
fSocket = 0;
}
}
Bool_t TFastCgi::Create(const char *args)
{
#ifndef HTTP_WITHOUT_FASTCGI
FCGX_Init();
TString sport = ":9000";
if ((args != 0) && (strlen(args) > 0)) {
sport = ":";
while ((*args != 0) && (*args >= '0') && (*args <= '9'))
sport.Append(*args++);
while ((*args != 0) && (*args != '?')) args++;
if (*args == '?') {
TUrl url(TString::Format("http://localhost/folder%s", args));
if (url.IsValid()) {
url.ParseOptions();
if (url.GetValueFromOptions("debug") != 0) fDebugMode = kTRUE;
const char *top = url.GetValueFromOptions("top");
if (top != 0) fTopName = top;
}
}
}
Info("Create", "Starting FastCGI server on port %s", sport.Data() + 1);
fSocket = FCGX_OpenSocket(sport.Data(), 10);
fThrd = new TThread("FastCgiThrd", TFastCgi::run_func, this);
fThrd->Run();
return kTRUE;
#else
(void)args;
Error("Create", "ROOT compiled without fastcgi support");
return kFALSE;
#endif
}
void *TFastCgi::run_func(void *args)
{
#ifndef HTTP_WITHOUT_FASTCGI
TFastCgi *engine = (TFastCgi *) args;
FCGX_Request request;
FCGX_InitRequest(&request, engine->GetSocket(), 0);
int count = 0;
while (1) {
int rc = FCGX_Accept_r(&request);
if (rc != 0) continue;
count++;
const char *inp_path = FCGX_GetParam("PATH_INFO", request.envp);
const char *inp_query = FCGX_GetParam("QUERY_STRING", request.envp);
const char *inp_method = FCGX_GetParam("REQUEST_METHOD", request.envp);
const char *inp_length = FCGX_GetParam("CONTENT_LENGTH", request.envp);
THttpCallArg arg;
if (inp_path != 0) arg.SetPathAndFileName(inp_path);
if (inp_query != 0) arg.SetQuery(inp_query);
if (inp_method != 0) arg.SetMethod(inp_method);
if (engine->fTopName.Length() > 0) arg.SetTopName(engine->fTopName.Data());
int len = 0;
if (inp_length!=0) len = strtol(inp_length, NULL, 10);
if (len>0) {
void* buf = malloc(len+1);
int nread = FCGX_GetStr((char*) buf, len, request.in);
if (nread>0) arg.SetPostData(buf, nread);
else free(buf);
}
TString header;
for (char **envp = request.envp; *envp != NULL; envp++) {
TString entry = *envp;
for (Int_t n=0;n<entry.Length();n++)
if (entry[n] == '=') { entry[n] = ':'; break; }
header.Append(entry);
header.Append("\r\n");
}
arg.SetRequestHeader(header);
if (engine->fDebugMode) {
FCGX_FPrintF(request.out,
"Status: 200 OK\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI echo</title>"
"<h1>FastCGI echo</h1>\n");
FCGX_FPrintF(request.out, "Request %d:<br/>\n<pre>\n", count);
FCGX_FPrintF(request.out, " Method : %s\n", arg.GetMethod());
FCGX_FPrintF(request.out, " PathName : %s\n", arg.GetPathName());
FCGX_FPrintF(request.out, " FileName : %s\n", arg.GetFileName());
FCGX_FPrintF(request.out, " Query : %s\n", arg.GetQuery());
FCGX_FPrintF(request.out, " PostData : %ld\n", arg.GetPostDataLength());
FCGX_FPrintF(request.out, "</pre><p>\n");
FCGX_FPrintF(request.out, "Environment:<br/>\n<pre>\n");
for (char **envp = request.envp; *envp != NULL; envp++) {
FCGX_FPrintF(request.out, " %s\n", *envp);
}
FCGX_FPrintF(request.out, "</pre><p>\n");
FCGX_Finish_r(&request);
continue;
}
TString fname;
if (engine->GetServer()->IsFileRequested(inp_path, fname)) {
FCGX_ROOT_send_file(&request, fname.Data());
FCGX_Finish_r(&request);
continue;
}
TString hdr;
if (!engine->GetServer()->ExecuteHttp(&arg) || arg.Is404()) {
arg.FillHttpHeader(hdr, "Status:");
FCGX_FPrintF(request.out, hdr.Data());
} else if (arg.IsFile()) {
FCGX_ROOT_send_file(&request, (const char *) arg.GetContent());
} else {
if (arg.GetZipping() > 0) arg.CompressWithGzip();
arg.FillHttpHeader(hdr, "Status:");
FCGX_FPrintF(request.out, hdr.Data());
FCGX_PutStr((const char *) arg.GetContent(),
(int) arg.GetContentLength(), request.out);
}
FCGX_Finish_r(&request);
}
return 0;
#else
return args;
#endif
}