part II of rewriting
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@635 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
429
core/app.cpp
429
core/app.cpp
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "app.h"
|
||||
#include "plugin.h"
|
||||
#include "misc.h"
|
||||
#include "functions/functions.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -37,8 +41,6 @@ App::App()
|
||||
system.SetConfig(&config);
|
||||
system.SetRequest(&request);
|
||||
system.SetDb(&db);
|
||||
system.SetFunctions(&functions); // !! czy model musi cos wiedziec o funkcjach?
|
||||
system.SetTemplates(&templates);
|
||||
|
||||
templates_notify.SetConfig(&config);
|
||||
|
||||
@@ -59,6 +61,7 @@ App::App()
|
||||
session_manager.SetRequest(&request);
|
||||
session_manager.SetSystem(&system);
|
||||
|
||||
post_multi_parser.SetConfig(&config);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,13 +131,12 @@ return true;
|
||||
|
||||
bool App::Init()
|
||||
{
|
||||
request.Init();
|
||||
|
||||
if( !CreateFCGISocket() )
|
||||
return false;
|
||||
|
||||
request.Clear();
|
||||
compress.Init();
|
||||
system.Init();
|
||||
|
||||
functions.Create();
|
||||
|
||||
// !! teraz mamy dwa katalogi z templetami
|
||||
@@ -194,10 +196,9 @@ return true;
|
||||
}
|
||||
|
||||
|
||||
void App::ProcessRequest()
|
||||
void App::ProcessRequestThrow()
|
||||
{
|
||||
request.Clear(); // !! dac na koniec
|
||||
request.Read();
|
||||
ReadRequest();
|
||||
|
||||
// when BaseUrlRedirect() return true we didn't have to set everything in request.Read()
|
||||
// in the future request.Read() can be split and at the beginning only environment variables will be read
|
||||
@@ -216,14 +217,30 @@ void App::ProcessRequest()
|
||||
Make();
|
||||
}
|
||||
|
||||
request.SendAll(); // !! czemu request sam sie chce wyslac? wrzucic to tutaj do app
|
||||
SendAnswer();
|
||||
notify.ItemChanged(request.notify_code);
|
||||
|
||||
if( request.function )
|
||||
request.function->Clear();
|
||||
}
|
||||
|
||||
|
||||
void App::ProcessRequest()
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessRequestThrow();
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
log << log1 << "App: there was an exception: std::exception: " << e.what() << logend;
|
||||
}
|
||||
catch(const Error & e)
|
||||
{
|
||||
log << log1 << "App: there was an exception: Error: " << e << logend;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
log << log1 << "App: there was an unknown exception" << logend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void App::Start()
|
||||
@@ -231,41 +248,15 @@ void App::Start()
|
||||
while( FCGX_Accept(&request.in, &request.out, &request.err, &request.env) == 0 )
|
||||
{
|
||||
system.load_avg.StartRequest();
|
||||
log << log2 << "---------------------------------------------------------------------------------" << logend;
|
||||
log << log2 << config.log_delimiter << logend;
|
||||
|
||||
try
|
||||
{
|
||||
ProcessRequest();
|
||||
}
|
||||
catch(const std::logic_error & e)
|
||||
{
|
||||
log << log1 << "std logic exception: " << e.what() << logend;
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
log << log1 << "std exception: " << e.what() << logend;
|
||||
}
|
||||
catch(const Error & e)
|
||||
{
|
||||
log << log1 << "exception: Error: " << e << logend;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
log << log1 << "uncaught unknown exception" << logend;
|
||||
}
|
||||
|
||||
ProcessRequest();
|
||||
SaveSessionsIfNeeded();
|
||||
|
||||
// !! this should be immediately after FCGX_Accept() but signals don't want to break FCGX_Accept
|
||||
//if( signal_hup )
|
||||
if( false )
|
||||
{
|
||||
log << logsave;
|
||||
FCGX_Finish();
|
||||
return;
|
||||
}
|
||||
if( request.function )
|
||||
request.function->Clear();
|
||||
|
||||
request.ClearPostFileTmp();
|
||||
request.Clear();
|
||||
system.load_avg.StopRequest();
|
||||
log << logsave;
|
||||
}
|
||||
@@ -292,6 +283,7 @@ void App::MakePage()
|
||||
{
|
||||
bool sent = false;
|
||||
|
||||
|
||||
if( !request.redirect_to.empty() || !request.x_sendfile.empty() )
|
||||
return;
|
||||
|
||||
@@ -328,7 +320,7 @@ void App::Make()
|
||||
return;
|
||||
}
|
||||
|
||||
// request->status can be changed by function_parser
|
||||
// request.status can be changed by function_parser
|
||||
if( request.status == WINIX_ERR_OK )
|
||||
{
|
||||
if( system.DirsHaveReadExecPerm() )
|
||||
@@ -361,13 +353,354 @@ void App::Make()
|
||||
plugin.Call(WINIX_CONTENT_MAKE);
|
||||
MakePage();
|
||||
|
||||
// !! dodac parametr do konfiga wlaczajacy te informacje
|
||||
//request->PrintGetTab();
|
||||
//request->PrintEnv();
|
||||
//request->PrintIn();
|
||||
if( config.debug_info )
|
||||
{
|
||||
// !! dodac inne informacje (get, post, itp)
|
||||
// jesli jest debug_info wlaczone to nie robic przekierowan
|
||||
request.PrintGetTab();
|
||||
request.PrintEnv();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void App::ReadRequest()
|
||||
{
|
||||
ReadEnvVariables();
|
||||
CheckRequestMethod();
|
||||
CheckFCGIRole();
|
||||
|
||||
LogAccess();
|
||||
|
||||
ReadGetPostVars();
|
||||
cookie_parser.Parse(request.env_http_cookie, request.cookie_tab);
|
||||
accept_encoding_parser.Parse(request.env_http_accept_encoding);
|
||||
|
||||
CheckIE();
|
||||
CheckKonqueror();
|
||||
|
||||
if( request.role == Request::authorizer )
|
||||
log << log3 << "Request: fast cgi role: authorizer" << logend;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::SetEnv(const char * & env, const char * name)
|
||||
{
|
||||
const char * v = FCGX_GetParam(name, request.env);
|
||||
|
||||
if( v )
|
||||
env = v;
|
||||
|
||||
// by default env is set to an empty string (in request.Clear() method)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::ReadEnvVariables()
|
||||
{
|
||||
// we store that values because FCGX_GetParam has O(n) complexity
|
||||
// with this variables (env_*) we have O(1)
|
||||
|
||||
SetEnv(request.env_request_method, "REQUEST_METHOD");
|
||||
SetEnv(request.env_request_uri, "REQUEST_URI");
|
||||
SetEnv(request.env_http_cookie, "HTTP_COOKIE");
|
||||
SetEnv(request.env_remote_addr, "REMOTE_ADDR");
|
||||
SetEnv(request.env_http_host, "HTTP_HOST");
|
||||
SetEnv(request.env_http_user_agent, "HTTP_USER_AGENT");
|
||||
SetEnv(request.env_fcgi_role, "FCGI_ROLE");
|
||||
SetEnv(request.env_content_type, "CONTENT_TYPE");
|
||||
SetEnv(request.env_http_accept_encoding,"HTTP_ACCEPT_ENCODING");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::CheckRequestMethod()
|
||||
{
|
||||
request.method = Request::none;
|
||||
|
||||
if( ToSmall(request.env_request_method[0]) == 'g' )
|
||||
request.method = Request::get;
|
||||
else
|
||||
if( ToSmall(request.env_request_method[0]) == 'p' )
|
||||
request.method = Request::post;
|
||||
else
|
||||
if( ToSmall(request.env_request_method[0]) == 'h' )
|
||||
request.method = Request::head;
|
||||
}
|
||||
|
||||
|
||||
void App::CheckFCGIRole()
|
||||
{
|
||||
// default we assume 'responder'
|
||||
request.role = Request::responder;
|
||||
|
||||
if( ToSmall(request.env_fcgi_role[0]) == 'a' )
|
||||
request.role = Request::authorizer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::LogAccess()
|
||||
{
|
||||
log.PutDate(log1);
|
||||
|
||||
log << request.env_remote_addr << ' '
|
||||
<< request.env_request_method << ' '
|
||||
<< request.env_http_host
|
||||
<< request.env_request_uri << ' '
|
||||
<< request.env_http_user_agent << logend;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void App::ReadGetPostVars()
|
||||
{
|
||||
// get parameters we have always
|
||||
get_parser.Parse(request.env_request_uri, request.get_tab);
|
||||
|
||||
if( request.method == Request::post )
|
||||
{
|
||||
if( IsSubStringNoCase("multipart/form-data", request.env_content_type) )
|
||||
{
|
||||
log << log3 << "Request: post content type: multipart/form-data" << logend;
|
||||
post_multi_parser.Parse(request.in, request.post_tab, request.post_file_tab);
|
||||
}
|
||||
else
|
||||
{
|
||||
post_parser.Parse(request.in, request.post_tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void App::CheckIE()
|
||||
{
|
||||
char * msie = strstr(request.env_http_user_agent, "MSIE");
|
||||
|
||||
if( msie )
|
||||
request.browser_msie = true;
|
||||
else
|
||||
request.browser_msie = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::CheckKonqueror()
|
||||
{
|
||||
char * kon = strstr(request.env_http_user_agent, "Konqueror");
|
||||
|
||||
if( kon )
|
||||
request.browser_konqueror = true;
|
||||
else
|
||||
request.browser_konqueror = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void App::PrepareSessionCookie()
|
||||
{
|
||||
if( !request.session || request.session->id==0 )
|
||||
return;
|
||||
|
||||
if( !request.session->puser || !request.session->remember_me )
|
||||
{
|
||||
request.SetCookie(config.http_session_id_name.c_str(), request.session->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
time_t t = time(0) + config.session_remember_max_idle;
|
||||
tm * expires = localtime(&t);
|
||||
|
||||
if( !expires )
|
||||
{
|
||||
// oops, something wrong
|
||||
request.SetCookie(config.http_session_id_name.c_str(), request.session->id);
|
||||
return;
|
||||
}
|
||||
|
||||
request.SetCookie(config.http_session_id_name.c_str(), request.session->id, expires);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void App::SendHeaders(bool compressing, Header header)
|
||||
{
|
||||
PrepareSessionCookie();
|
||||
|
||||
if( request.send_as_attachment )
|
||||
FCGX_PutS("Content-Disposition: attachment\r\n", request.out);
|
||||
|
||||
if( !request.redirect_to.empty() )
|
||||
{
|
||||
FCGX_PutS("Status: 301 Moved Permanently\r\n", request.out);
|
||||
FCGX_FPrintF(request.out, "Location: %s\r\n", request.redirect_to.c_str());
|
||||
log << log2 << "Redirect to: " << request.redirect_to << logend;
|
||||
}
|
||||
else
|
||||
if( !request.x_sendfile.empty() )
|
||||
{
|
||||
FCGX_FPrintF(request.out, "%s: %s\r\n", config.http_header_send_file.c_str(),
|
||||
request.x_sendfile.c_str());
|
||||
FCGX_PutS("Status: 200 OK\r\n", request.out);
|
||||
log << log2 << "Sending file: " << request.x_sendfile << logend;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( header )
|
||||
{
|
||||
case h_404:
|
||||
FCGX_PutS("Status: 404 Not Found\r\n", request.out);
|
||||
FCGX_PutS("Content-Type: text/html\r\n", request.out);
|
||||
log << log2 << "Request: response: 404 Not Found" << logend;
|
||||
break;
|
||||
|
||||
case h_403:
|
||||
FCGX_PutS("Status: 403 Forbidden\r\n", request.out);
|
||||
FCGX_PutS("Content-Type: text/html\r\n", request.out);
|
||||
log << log2 << "Request: response: 403 Forbidden" << logend;
|
||||
break;
|
||||
|
||||
default:
|
||||
FCGX_PutS("Status: 200 OK\r\n", request.out);
|
||||
|
||||
if( request.role != Request::authorizer )
|
||||
FCGX_PutS("Content-Type: text/html\r\n", request.out);
|
||||
}
|
||||
}
|
||||
|
||||
if( compressing )
|
||||
FCGX_PutS("Content-Encoding: deflate\r\n", request.out);
|
||||
|
||||
FCGX_PutS(request.headers.str().c_str(), request.out);
|
||||
FCGX_PutS("\r\n", request.out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::SetHtmlFilterConf()
|
||||
{
|
||||
html_filter.TrimWhite(config.html_filter_trim_white);
|
||||
html_filter.BreakLines(config.html_filter_break_lines);
|
||||
html_filter.InsertTabs(config.html_filter_tabs);
|
||||
|
||||
if( config.html_filter_orphans )
|
||||
html_filter.CheckOrphans(config.html_filter_orphans_lang, config.html_filter_orphans_mode);
|
||||
}
|
||||
|
||||
|
||||
// !! kopiowanie tych stringow bedzie zmienione
|
||||
// gdy bedziemy korzystac w przyszlosci z wlasnego stringstream
|
||||
void App::FilterCompressSend(bool compressing, const std::string & source_ref)
|
||||
{
|
||||
const std::string * source = &source_ref;
|
||||
|
||||
bool raw = request.is_item && request.item.content_type == Item::ct_raw && request.status == WINIX_ERR_OK &&
|
||||
request.function && (request.function->fun.url == "cat" || request.function->fun.url == "run");
|
||||
|
||||
if( config.html_filter && !raw )
|
||||
{
|
||||
SetHtmlFilterConf();
|
||||
html_filter.Filter(*source, clean_html);
|
||||
AddDebugInfo(clean_html);
|
||||
source = &clean_html;
|
||||
}
|
||||
else
|
||||
{
|
||||
html_with_debug = *source;
|
||||
AddDebugInfo(html_with_debug);
|
||||
source = &html_with_debug;
|
||||
}
|
||||
|
||||
|
||||
if( compressing )
|
||||
compress.CompressAndPut(source->c_str(), source->length(), request.out);
|
||||
else
|
||||
FCGX_PutS(source->c_str(), request.out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool App::IsCompressionAllowed(const std::string & source)
|
||||
{
|
||||
return( config.compression &&
|
||||
request.role == Request::responder &&
|
||||
request.redirect_to.empty() &&
|
||||
request.x_sendfile.empty() &&
|
||||
!request.browser_msie &&
|
||||
!request.browser_konqueror &&
|
||||
accept_encoding_parser.AcceptDeflate() &&
|
||||
source.size() >= (size_t)config.compression_page_min_size );
|
||||
}
|
||||
|
||||
|
||||
bool App::CanSendContent(Header header)
|
||||
{
|
||||
if( !request.redirect_to.empty() || !request.x_sendfile.empty() )
|
||||
// if there is a redirect or a file to send then we do not send a content
|
||||
return false;
|
||||
|
||||
if( header == h_200 && request.role == Request::authorizer && request.is_item && request.item.auth != Item::auth_none )
|
||||
// if there is an item and the item has 'file' storage we do not send a content
|
||||
return false;
|
||||
|
||||
/*
|
||||
we don't have to check the HEAD method
|
||||
the server (lighttpd) doesn't send the body of its own
|
||||
*/
|
||||
if( request.method == Request::head )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void App::AddDebugInfo(std::string & out)
|
||||
{
|
||||
if( config.debug_info )
|
||||
{
|
||||
const std::string & d = request.debug.str();
|
||||
|
||||
if( !d.empty() )
|
||||
{
|
||||
out += "\n<!--\n";
|
||||
out += d;
|
||||
out += "\n-->\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void App::SendAnswer()
|
||||
{
|
||||
const std::string & source = request.page.str();
|
||||
Header header = h_200;
|
||||
bool compressing = IsCompressionAllowed(source);
|
||||
Error status = request.status;
|
||||
|
||||
if( status == WINIX_ERR_NO_ITEM || status == WINIX_ERR_NO_FUNCTION || status == WINIX_ERR_UNKNOWN_PARAM )
|
||||
header = h_404;
|
||||
|
||||
if( status == WINIX_ERR_PERMISSION_DENIED || status == WINIX_ERR_CANT_CHANGE_USER || status == WINIX_ERR_CANT_CHANGE_GROUP )
|
||||
header = h_403;
|
||||
|
||||
SendHeaders(compressing, header);
|
||||
|
||||
if( CanSendContent(header) )
|
||||
{
|
||||
// filtering (html), compressing (deflate) and sending back to the web browser
|
||||
FilterCompressSend(compressing, source);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user