/* * 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(); // !! dac na koniec 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(); Make(); } request.SendAll(); // !! czemu request sam sie chce wyslac? wrzucic to tutaj do app notify.ItemChanged(request.notify_code); if( request.function ) request.function->Clear(); } 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.function ) { if( request.function->fun.url == "cat" ) { request.page << request.item.content; sent = true; } else if( request.function->fun.url == "run" ) { templates.GenerateRunRaw(); sent = true; } } if( !sent ) { templates.Generate(); } } void App::Make() { if( request.dir_tab.empty() ) { log << log1 << "Content: there is no a root dir (dir_tab 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_tab.empty() ) { log << log1 << "App: there is no a root dir (dir_tab is empty -- after calling a function)" << logend; return; } plugin.Call(WINIX_CONTENT_MAKE); MakePage(); // !! dodac parametr do konfiga wlaczajacy te informacje //request->PrintGetTab(); //request->PrintEnv(); //request->PrintIn(); }