399 lines
7.7 KiB
C++
399 lines
7.7 KiB
C++
|
/*
|
||
|
* This file is a part of Winix
|
||
|
* and is not publicly distributed
|
||
|
*
|
||
|
* Copyright (c) 2010, Tomasz Sowa
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "app.h"
|
||
|
#include "plugin.h"
|
||
|
|
||
|
|
||
|
|
||
|
App::App()
|
||
|
{
|
||
|
stdout_is_closed = false;
|
||
|
last_sessions_save = time(0);
|
||
|
|
||
|
plugin.SetDb(&db);
|
||
|
plugin.SetConfig(&config);
|
||
|
plugin.SetRequest(&request);
|
||
|
plugin.SetSystem(&system);
|
||
|
plugin.SetFunctions(&functions);
|
||
|
plugin.SetTemplates(&templates);
|
||
|
plugin.SetSessionManager(&session_manager);
|
||
|
|
||
|
request.SetConfig(&config);
|
||
|
|
||
|
functions.SetConfig(&config);
|
||
|
functions.SetRequest(&request);
|
||
|
functions.SetDb(&db);
|
||
|
functions.SetSystem(&system);
|
||
|
functions.SetTemplates(&templates);
|
||
|
functions.SetNotify(¬ify);
|
||
|
|
||
|
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);
|
||
|
|
||
|
notify.SetRequest(&request);
|
||
|
notify.SetConfig(&config);
|
||
|
notify.SetSystem(&system);
|
||
|
notify.SetTemplatesNotify(&templates_notify);
|
||
|
|
||
|
templates.SetConfig(&config);
|
||
|
templates.SetRequest(&request);
|
||
|
templates.SetDb(&db);
|
||
|
templates.SetSystem(&system);
|
||
|
templates.SetFunctions(&functions);
|
||
|
templates.SetSessionManager(&session_manager);
|
||
|
|
||
|
session_manager.SetLastContainer(&system.users.last);
|
||
|
session_manager.SetConfig(&config);
|
||
|
session_manager.SetRequest(&request);
|
||
|
session_manager.SetSystem(&system);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool App::CreateFCGISocket()
|
||
|
{
|
||
|
const char * sock = config.fcgi_socket.c_str();
|
||
|
|
||
|
unlink(sock);
|
||
|
|
||
|
|
||
|
|
||
|
int s = FCGX_OpenSocket(sock, 10);
|
||
|
|
||
|
if( s < 0 )
|
||
|
{
|
||
|
log << log1 << "An error during creating a socket" << logend;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
chmod(sock, config.fcgi_socket_chmod);
|
||
|
|
||
|
passwd * pw = getpwnam(config.fcgi_socket_user.c_str());
|
||
|
|
||
|
if( !pw )
|
||
|
{
|
||
|
log << log1 << "There is no user: " << config.fcgi_socket_user << logend;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
group * gr = getgrnam(config.fcgi_socket_group.c_str());
|
||
|
|
||
|
if( !gr )
|
||
|
{
|
||
|
log << log1 << "There is no group: " << config.fcgi_socket_group << logend;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
chown(sock, pw->pw_uid, gr->gr_gid);
|
||
|
|
||
|
|
||
|
if( setuid(pw->pw_uid) < 0 )
|
||
|
{
|
||
|
log << log1 << "I can't change the user into: " << config.fcgi_socket_user << logend;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
if( setgid(gr->gr_gid) < 0 )
|
||
|
{
|
||
|
int e = errno;
|
||
|
|
||
|
log << log1 << "I can't change the group into: " << config.fcgi_socket_group << " " << gr->gr_gid << logend;
|
||
|
log << log1 << "errno: " << e << logend;
|
||
|
return false;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
dup2(s, 0);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool App::Init()
|
||
|
{
|
||
|
request.Init();
|
||
|
|
||
|
if( !CreateFCGISocket() )
|
||
|
return false;
|
||
|
|
||
|
system.Init();
|
||
|
|
||
|
functions.Create();
|
||
|
|
||
|
// !! teraz mamy dwa katalogi z templetami
|
||
|
// !! o co chodzilo?
|
||
|
if( !notify.Init() )
|
||
|
return false;
|
||
|
|
||
|
|
||
|
templates.ReadIndexFileNames();
|
||
|
templates.ReadTemplates();
|
||
|
templates.CreateFunctions();
|
||
|
|
||
|
|
||
|
session_manager.LoadSessions();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void App::Close()
|
||
|
{
|
||
|
session_manager.SaveSessions();
|
||
|
session_manager.DeleteAllPluginsData();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool App::BaseUrlRedirect()
|
||
|
{
|
||
|
if( request.role == Request::responder )
|
||
|
{
|
||
|
if( config.base_url_http_host.empty() )
|
||
|
return false;
|
||
|
|
||
|
if( config.base_url_http_host == request.env_http_host )
|
||
|
return false;
|
||
|
|
||
|
request.redirect_to = config.base_url + request.env_request_uri;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// authorizer
|
||
|
|
||
|
if( config.base_url_auth_http_host.empty() )
|
||
|
return false;
|
||
|
|
||
|
if( config.base_url_auth_http_host == request.env_http_host )
|
||
|
return false;
|
||
|
|
||
|
request.redirect_to = config.base_url_auth + request.env_request_uri;
|
||
|
}
|
||
|
|
||
|
log << log3 << "RC: BaseUrlRedirect from: " << request.env_http_host << logend;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void App::ProcessRequest()
|
||
|
{
|
||
|
request.Clear();
|
||
|
request.Read();
|
||
|
|
||
|
// 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
|
||
|
// and then BaseUrlRedirect() will be called (for performance)
|
||
|
if( !BaseUrlRedirect() )
|
||
|
{
|
||
|
session_manager.DeleteOldSessions();
|
||
|
session_manager.SetSession(); // set request.session as well
|
||
|
|
||
|
// !! tutaj dodac to ustawianie request.session
|
||
|
|
||
|
functions.Parse();
|
||
|
|
||
|
system.mounts.CalcCurMount();
|
||
|
|
||
|
ReadAdditionalInfo();
|
||
|
Make();
|
||
|
}
|
||
|
|
||
|
request.SendAll(); // !! czemu request sam sie chce wyslac? wrzucic to tutaj do app
|
||
|
notify.ItemChanged(request.notify_code);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void App::Start()
|
||
|
{
|
||
|
while( FCGX_Accept(&request.in, &request.out, &request.err, &request.env) == 0 )
|
||
|
{
|
||
|
system.load_avg.StartRequest();
|
||
|
log << log2 << "---------------------------------------------------------------------------------" << 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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
request.ClearPostFileTmp();
|
||
|
system.load_avg.StopRequest();
|
||
|
log << logsave;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void App::SaveSessionsIfNeeded()
|
||
|
{
|
||
|
time_t t = time(0);
|
||
|
|
||
|
if( last_sessions_save + 86400 > t )
|
||
|
return;
|
||
|
|
||
|
// saving once a day for safety
|
||
|
last_sessions_save = t;
|
||
|
session_manager.SaveSessions();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// !! zmienic na lepsza nazwe
|
||
|
void App::MakePage()
|
||
|
{
|
||
|
bool sent = false;
|
||
|
|
||
|
if( !request.redirect_to.empty() || !request.x_sendfile.empty() )
|
||
|
return;
|
||
|
|
||
|
|
||
|
if( request.is_item && request.item.auth == Item::auth_none &&
|
||
|
request.item.content_type == Item::ct_raw && request.status == WINIX_ERR_OK && request.pfunction )
|
||
|
{
|
||
|
if( request.pfunction->fun.url == "cat" )
|
||
|
{
|
||
|
request.page << request.item.content;
|
||
|
sent = true;
|
||
|
}
|
||
|
else
|
||
|
if( request.pfunction->fun.url == "run" )
|
||
|
{
|
||
|
templates.GenerateRunRaw();
|
||
|
sent = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( !sent )
|
||
|
{
|
||
|
templates.Generate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void App::Make()
|
||
|
{
|
||
|
if( request.dir_table.empty() )
|
||
|
{
|
||
|
log << log1 << "Content: there is no a root dir (dir_table is empty)" << logend;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// request->status can be changed by function_parser
|
||
|
if( request.status == WINIX_ERR_OK )
|
||
|
{
|
||
|
if( system.DirsHaveReadExecPerm() )
|
||
|
{
|
||
|
if( request.method == Request::post )
|
||
|
functions.MakePost();
|
||
|
|
||
|
if( request.redirect_to.empty() && request.status == WINIX_ERR_OK )
|
||
|
functions.MakeGet();
|
||
|
}
|
||
|
else
|
||
|
request.status = WINIX_ERR_PERMISSION_DENIED;
|
||
|
}
|
||
|
|
||
|
if( request.session->spam_score > 0 )
|
||
|
log << log1 << "App: spam score: " << request.session->spam_score << logend;
|
||
|
|
||
|
if( request.IsParam("noredirect") )
|
||
|
request.redirect_to.clear();
|
||
|
|
||
|
if( !request.redirect_to.empty() )
|
||
|
return;
|
||
|
|
||
|
if( request.dir_table.empty() )
|
||
|
{
|
||
|
log << log1 << "App: there is no a root dir (dir_table is empty -- after calling a function)" << logend;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
plugin.Call(WINIX_CONTENT_MAKE);
|
||
|
MakePage();
|
||
|
|
||
|
// !! dodac parametr do konfiga wlaczajacy te informacje
|
||
|
//request->PrintGetTable();
|
||
|
//request->PrintEnv();
|
||
|
//request->PrintIn();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// !! dac lepsza nazwe i czy napewno w app to ma byc?
|
||
|
void App::ReadAdditionalInfo()
|
||
|
{
|
||
|
if( request.dir_table.empty() )
|
||
|
return;
|
||
|
|
||
|
if( system.mounts.pmount->type == Mount::thread )
|
||
|
{
|
||
|
if( db.GetThreadByDirId(request.dir_table.back()->id, request.thread) == WINIX_ERR_OK )
|
||
|
request.is_thread = true;
|
||
|
}
|
||
|
else
|
||
|
if( system.mounts.pmount->type == Mount::ticket )
|
||
|
{
|
||
|
if( db.GetTicketByDirId(request.dir_table.back()->id, request.ticket) == WINIX_ERR_OK )
|
||
|
{
|
||
|
request.is_ticket = true;
|
||
|
|
||
|
if( !request.is_item && (!request.pfunction || request.pfunction->fun.url == "ticket") )
|
||
|
{
|
||
|
db.GetItemById(request.ticket.item_id, request.item);
|
||
|
// don't set request->is_item here
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|