2010-08-10 18:12:50 +02:00
|
|
|
/*
|
|
|
|
* This file is a part of Winix
|
2014-10-04 20:04:03 +02:00
|
|
|
* and is distributed under the 2-Clause BSD licence.
|
|
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2019-03-19 19:08:09 +01:00
|
|
|
* Copyright (c) 2010-2019, Tomasz Sowa
|
2010-08-10 18:12:50 +02:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
2014-10-04 20:04:03 +02:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
2010-08-10 18:12:50 +02:00
|
|
|
*/
|
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
#include <sys/types.h>
|
2015-01-02 08:01:08 +01:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2010-10-24 21:26:54 +02:00
|
|
|
#include <pwd.h>
|
2010-10-24 19:49:38 +02:00
|
|
|
#include <grp.h>
|
|
|
|
#include <unistd.h>
|
2010-12-02 02:02:02 +01:00
|
|
|
#include <signal.h>
|
2012-10-27 09:44:26 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
2013-12-09 17:03:45 +01:00
|
|
|
#include <utility>
|
2015-01-02 08:01:08 +01:00
|
|
|
#include <fastcgi.h>
|
2015-01-02 08:14:15 +01:00
|
|
|
#include <stddef.h>
|
2010-08-10 18:12:50 +02:00
|
|
|
#include "app.h"
|
|
|
|
#include "plugin.h"
|
2010-08-12 21:10:12 +02:00
|
|
|
#include "misc.h"
|
|
|
|
#include "functions/functions.h"
|
2012-01-12 03:24:08 +01:00
|
|
|
#include "utf8/utf8.h"
|
2018-05-25 19:22:12 +02:00
|
|
|
#include "convert/convert.h"
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
|
2014-02-12 17:30:49 +01:00
|
|
|
namespace Winix
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
App::App()
|
|
|
|
{
|
|
|
|
stdout_is_closed = false;
|
2010-10-24 01:12:47 +02:00
|
|
|
last_sessions_save = std::time(0);
|
2010-11-23 22:52:25 +01:00
|
|
|
fcgi_socket = -1;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2018-11-21 23:53:24 +01:00
|
|
|
file_log.set_synchro(&synchro);
|
|
|
|
file_log.set_time_zones(&system.time_zones);
|
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
log.SetLogBuffer(&log_buffer);
|
|
|
|
log.SetFileLog(&file_log);
|
|
|
|
|
|
|
|
// objects dependency for main thread
|
|
|
|
winix_base.set_config(&config);
|
|
|
|
winix_base.set_log_buffer(&log_buffer);
|
|
|
|
winix_base.set_file_log(&file_log);
|
|
|
|
winix_base.set_synchro(&synchro);
|
|
|
|
|
|
|
|
winix_model.set_dependency(&winix_base);
|
|
|
|
winix_model.set_plugin(&plugin);
|
|
|
|
winix_model.set_model_connector(&model_connector);
|
|
|
|
|
|
|
|
winix_system.set_dependency(&winix_model);
|
|
|
|
winix_system.set_system(&system);
|
|
|
|
|
|
|
|
winix_request.set_dependency(&winix_system);
|
|
|
|
winix_request.set_cur(&cur);
|
|
|
|
winix_request.set_session_manager(&session_manager);
|
|
|
|
winix_request.set_locale(&TemplatesFunctions::locale);
|
|
|
|
// //////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
config.SetFileLog(&file_log);
|
2018-11-21 23:53:24 +01:00
|
|
|
config.SetLogBuffer(&log_buffer);
|
2018-11-21 12:03:53 +01:00
|
|
|
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
// temporary there is only one request
|
|
|
|
cur.request = &req;
|
|
|
|
cur.session = session_manager.GetTmpSession();
|
2011-06-21 23:24:49 +02:00
|
|
|
cur.mount = system.mounts.GetEmptyMount();
|
2011-01-23 15:15:30 +01:00
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
db_conn.set_dependency(&winix_base);
|
|
|
|
|
|
|
|
db.set_dependency(&winix_base);
|
2010-09-18 02:51:12 +02:00
|
|
|
db.SetConn(db_conn);
|
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
plugin.set_dependency(&winix_base);
|
2010-08-10 18:12:50 +02:00
|
|
|
plugin.SetDb(&db);
|
2018-11-21 12:03:53 +01:00
|
|
|
//plugin.SetConfig(&config);
|
2011-01-23 15:15:30 +01:00
|
|
|
plugin.SetCur(&cur);
|
2010-08-10 18:12:50 +02:00
|
|
|
plugin.SetSystem(&system);
|
|
|
|
plugin.SetFunctions(&functions);
|
|
|
|
plugin.SetTemplates(&templates);
|
2018-11-21 12:03:53 +01:00
|
|
|
//plugin.SetSynchro(&synchro);
|
2010-08-10 18:12:50 +02:00
|
|
|
plugin.SetSessionManager(&session_manager);
|
2018-11-21 18:51:15 +01:00
|
|
|
plugin.SetWinixRequest(&winix_request);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
req.SetConfig(&config);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
functions.set_dependency(&winix_request);
|
|
|
|
// functions.set_config(&config);
|
|
|
|
// functions.set_file_log(&file_log);
|
|
|
|
// functions.set_model_connector(&model_connector);
|
|
|
|
// functions.set_synchro(&synchro);
|
|
|
|
|
|
|
|
//functions.SetConfig(&config);
|
2011-01-23 15:15:30 +01:00
|
|
|
functions.SetCur(&cur);
|
2010-08-10 18:12:50 +02:00
|
|
|
functions.SetDb(&db);
|
|
|
|
functions.SetSystem(&system);
|
|
|
|
functions.SetTemplates(&templates);
|
2018-11-21 12:03:53 +01:00
|
|
|
//functions.SetSynchro(&synchro);
|
2012-10-27 09:44:26 +02:00
|
|
|
functions.SetSessionManager(&session_manager);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
|
|
|
|
system.set_dependency(&winix_model);
|
|
|
|
//system.SetConfig(&config);
|
2011-01-23 15:15:30 +01:00
|
|
|
system.SetCur(&cur);
|
2010-08-10 18:12:50 +02:00
|
|
|
system.SetDb(&db);
|
2018-11-21 12:03:53 +01:00
|
|
|
//system.SetSynchro(&synchro);
|
2011-09-14 11:56:00 +02:00
|
|
|
system.SetFunctions(&functions);
|
2012-03-09 03:36:25 +01:00
|
|
|
system.SetSessionManager(&session_manager);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2018-11-21 18:51:15 +01:00
|
|
|
templates.set_dependency(&winix_request);
|
2010-08-10 18:12:50 +02:00
|
|
|
templates.SetConfig(&config);
|
2011-01-23 15:15:30 +01:00
|
|
|
templates.SetCur(&cur);
|
2010-08-10 18:12:50 +02:00
|
|
|
templates.SetDb(&db);
|
|
|
|
templates.SetSystem(&system);
|
|
|
|
templates.SetFunctions(&functions);
|
|
|
|
templates.SetSessionManager(&session_manager);
|
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
session_manager.set_dependency(&winix_model); // zobaczyc czy wskoczy do przeciazonej metody w session manager
|
2010-08-10 18:12:50 +02:00
|
|
|
session_manager.SetLastContainer(&system.users.last);
|
2011-01-23 15:15:30 +01:00
|
|
|
session_manager.SetCur(&cur);
|
2010-08-10 18:12:50 +02:00
|
|
|
session_manager.SetSystem(&system);
|
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
post_multi_parser.set_dependency(&winix_base);
|
2010-08-12 21:10:12 +02:00
|
|
|
post_multi_parser.SetConfig(&config);
|
2018-11-21 12:03:53 +01:00
|
|
|
}
|
|
|
|
|
2011-06-19 22:59:58 +02:00
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
|
2018-11-21 23:53:24 +01:00
|
|
|
void App::InitLoggers()
|
2018-11-21 12:03:53 +01:00
|
|
|
{
|
2018-11-21 23:53:24 +01:00
|
|
|
file_log.init(config.log_file, config.log_stdout, config.log_level, config.log_save_each_line, config.log_time_zone_id);
|
2018-11-23 18:53:43 +01:00
|
|
|
log.SetMaxRequests(config.log_request);
|
2018-11-21 23:53:24 +01:00
|
|
|
}
|
2018-11-21 18:51:15 +01:00
|
|
|
|
2018-11-21 23:53:24 +01:00
|
|
|
|
|
|
|
Log & App::GetMainLog()
|
|
|
|
{
|
|
|
|
return log;
|
2010-08-10 18:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-21 23:53:24 +01:00
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
void App::InitPlugins()
|
|
|
|
{
|
|
|
|
plugin.LoadPlugins(config.plugins_dir, config.plugin_file);
|
|
|
|
}
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
bool App::InitFCGI(char * sock, char * sock_user, char * sock_group)
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
if( !WideToUTF8(config.fcgi_socket, sock, WINIX_OS_PATH_SIZE) )
|
|
|
|
return false;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( !WideToUTF8(config.fcgi_socket_user, sock_user, WINIX_OS_USERNAME_SIZE) )
|
|
|
|
return false;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( !WideToUTF8(config.fcgi_socket_group, sock_group, WINIX_OS_USERNAME_SIZE) )
|
2010-08-10 18:12:50 +02:00
|
|
|
return false;
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
/*
|
|
|
|
* chmod and chown of the socket are set before winix drops privileges
|
|
|
|
*/
|
|
|
|
bool App::InitFCGIChmodChownSocket(char * sock, char * sock_user, char * sock_group)
|
|
|
|
{
|
|
|
|
if( chmod(sock, config.fcgi_socket_chmod) < 0 )
|
|
|
|
{
|
|
|
|
log << log1 << "App: I cannot chmod a FastCGI socket, check fcgi_socket_chmod in the config" << logend;
|
|
|
|
return false;
|
|
|
|
}
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
passwd * pw = getpwnam(sock_user);
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
if( !pw )
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
log << log1 << "App: there is no a user: " << config.fcgi_socket_user << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
group * gr = getgrnam(sock_group);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
if( !gr )
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
log << log1 << "App: there is no a group: " << config.fcgi_socket_group << logend;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( chown(sock, pw->pw_uid, gr->gr_gid) < 0 )
|
|
|
|
{
|
|
|
|
log << log1 << "App: I cannot chown a FastCGI socket, check fcgi_socket_user "
|
|
|
|
<< "and fcgi_socket_group in the config" << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool App::InitFCGI()
|
|
|
|
{
|
|
|
|
char sock[WINIX_OS_PATH_SIZE];
|
|
|
|
char sock_user[WINIX_OS_USERNAME_SIZE];
|
|
|
|
char sock_group[WINIX_OS_USERNAME_SIZE];
|
|
|
|
|
|
|
|
if( !InitFCGI(sock, sock_user, sock_group) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unlink(sock);
|
|
|
|
fcgi_socket = FCGX_OpenSocket(sock, config.fcgi_socket_listen);
|
|
|
|
|
|
|
|
if( fcgi_socket < 0 )
|
|
|
|
{
|
|
|
|
log << log1 << "App: An error during creating a fcgi socket" << logend;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
log << log3 << "App: FastCGI socket number: " << fcgi_socket << logend;
|
|
|
|
|
|
|
|
if( !InitFCGIChmodChownSocket(sock, sock_user, sock_group) )
|
|
|
|
return false;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2010-11-23 22:52:25 +01:00
|
|
|
if( FCGX_Init() != 0 )
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2010-11-23 22:52:25 +01:00
|
|
|
log << log1 << "App: FCGX_Init fails" << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-23 22:52:25 +01:00
|
|
|
if( FCGX_InitRequest(&fcgi_request, fcgi_socket, FCGI_FAIL_ACCEPT_ON_INTR) != 0 )
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2010-11-23 22:52:25 +01:00
|
|
|
log << log1 << "App: FCGX_InitRequest fails" << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool App::Init()
|
|
|
|
{
|
2018-11-21 12:03:53 +01:00
|
|
|
postgresql_connector.set_conn_param(config.db_database, config.db_user, config.db_pass);
|
2018-11-23 18:53:43 +01:00
|
|
|
postgresql_connector.set_logger(log);
|
|
|
|
postgresql_connector.set_log_queries(config.log_db_query);
|
2018-11-21 12:03:53 +01:00
|
|
|
postgresql_connector.wait_for_connection();
|
|
|
|
|
|
|
|
model_connector.set_flat_connector(json_connector);
|
|
|
|
model_connector.set_db_connector(postgresql_connector);
|
|
|
|
//model_connector.set_doc_connector(doc_html_connector);
|
|
|
|
|
2010-09-18 02:51:12 +02:00
|
|
|
db_conn.SetConnParam(config.db_database, config.db_user, config.db_pass);
|
|
|
|
db_conn.WaitForConnection();
|
2018-04-25 11:37:56 +02:00
|
|
|
db.PostgreSQLsmallerThan10(config.db_postgresql_smaller_than_10);
|
2010-09-18 02:51:12 +02:00
|
|
|
db.LogQueries(config.log_db_query);
|
2010-08-14 18:23:18 +02:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
cur.request->Clear();
|
2018-11-21 12:03:53 +01:00
|
|
|
compress.set_dependency(&winix_base);
|
2010-08-12 21:10:12 +02:00
|
|
|
compress.Init();
|
2010-08-10 18:12:50 +02:00
|
|
|
system.Init();
|
2018-11-21 12:03:53 +01:00
|
|
|
|
2010-11-04 17:46:19 +01:00
|
|
|
functions.Init();
|
2011-07-15 04:09:02 +02:00
|
|
|
templates.Init(); // init templates after functions are created
|
2010-11-25 23:42:24 +01:00
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
// init notify after templates (it uses locales from templates)
|
|
|
|
system.notify.ReadTemplates();
|
2014-11-22 16:30:56 +01:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
session_manager.InitTmpSession();
|
2014-11-22 16:30:56 +01:00
|
|
|
session_manager.InitBanList();
|
|
|
|
session_manager.InitCookieEncoding();
|
2010-08-10 18:12:50 +02:00
|
|
|
session_manager.LoadSessions();
|
|
|
|
|
2010-12-10 22:07:01 +01:00
|
|
|
CreateStaticTree();
|
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
post_parser.set_dependency(&winix_model);
|
2011-06-07 00:47:34 +02:00
|
|
|
post_parser.LogValueSize(config.log_post_value_size);
|
|
|
|
// post_multi_parser has a pointer to the config
|
|
|
|
|
2018-11-21 12:03:53 +01:00
|
|
|
cookie_parser.set_dependency(&winix_model);
|
|
|
|
|
|
|
|
accept_encoding_parser.set_dependency(&winix_base);
|
|
|
|
|
2012-03-17 06:11:23 +01:00
|
|
|
plugin.Call((Session*)0, WINIX_PLUGIN_INIT);
|
2010-08-14 18:23:18 +02:00
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void App::Close()
|
|
|
|
{
|
2018-11-21 12:03:53 +01:00
|
|
|
{
|
|
|
|
Winix::Lock lock(synchro);
|
|
|
|
|
|
|
|
plugin.Call((Winix::Session*)0, WINIX_CLOSE);
|
|
|
|
|
|
|
|
session_manager.SaveSessions();
|
|
|
|
session_manager.DeleteSessions();
|
|
|
|
cur.request->Clear();
|
|
|
|
session_manager.UninitTmpSession();
|
|
|
|
|
|
|
|
// now all sessions are cleared
|
|
|
|
}
|
|
|
|
|
|
|
|
WaitForThreads();
|
|
|
|
// now all others threads are terminated
|
2010-08-10 18:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-07 02:26:37 +02:00
|
|
|
void App::BaseUrlRedirect(int code, bool add_subdomain)
|
2011-09-07 00:46:15 +02:00
|
|
|
{
|
2018-04-22 23:26:56 +02:00
|
|
|
system.PutUrlProto(cur.request->redirect_to);
|
2012-06-07 02:26:37 +02:00
|
|
|
|
|
|
|
if( add_subdomain && !cur.request->subdomain.empty() )
|
|
|
|
{
|
|
|
|
cur.request->redirect_to += cur.request->subdomain;
|
|
|
|
cur.request->redirect_to += '.';
|
|
|
|
}
|
|
|
|
|
2011-09-07 00:46:15 +02:00
|
|
|
cur.request->redirect_to += config.base_url;
|
2014-10-09 22:44:56 +02:00
|
|
|
cur.request->redirect_to += cur.request->env_request_uri;
|
2012-02-19 01:59:08 +01:00
|
|
|
// cur.request->env_request_uri should not be UrlEncoded because it contains slashes
|
2011-09-07 00:46:15 +02:00
|
|
|
cur.request->redirect_type = code;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
bool App::BaseUrlRedirect()
|
|
|
|
{
|
2012-04-22 15:30:07 +02:00
|
|
|
plugin.Call((Session*)0, WINIX_BASE_URL_REDIRECT);
|
|
|
|
|
|
|
|
if( !cur.request->redirect_to.empty() )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if( !config.base_url_redirect )
|
|
|
|
return false;
|
|
|
|
|
2011-08-18 01:09:47 +02:00
|
|
|
if( config.base_url.empty() )
|
2010-12-10 22:07:01 +01:00
|
|
|
return false;
|
2011-09-17 00:46:42 +02:00
|
|
|
|
|
|
|
if( cur.request->method == Request::post )
|
|
|
|
return false;
|
2010-12-10 22:07:01 +01:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( config.base_url == cur.request->env_http_host )
|
2010-12-10 22:07:01 +01:00
|
|
|
return false;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2012-06-07 02:26:37 +02:00
|
|
|
BaseUrlRedirect(config.base_url_redirect_code, false);
|
2011-09-07 00:46:15 +02:00
|
|
|
log << log3 << "App: BaseUrlRedirect from: " << cur.request->env_http_host << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-07 02:26:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2012-09-24 22:31:01 +02:00
|
|
|
void App::CheckIfNeedSSLredirect()
|
2012-06-07 02:26:37 +02:00
|
|
|
{
|
|
|
|
if( cur.request->method == Request::post )
|
2012-09-24 20:38:35 +02:00
|
|
|
{
|
2012-09-24 22:31:01 +02:00
|
|
|
// something comes via POST, don't do the redirect because you lose the date
|
|
|
|
return;
|
2012-09-24 20:38:35 +02:00
|
|
|
}
|
2011-09-14 11:56:00 +02:00
|
|
|
|
2012-09-24 22:31:01 +02:00
|
|
|
if( config.use_ssl )
|
2012-09-24 20:38:35 +02:00
|
|
|
{
|
2015-05-29 11:24:43 +02:00
|
|
|
if( config.use_ssl_only_for_logged_users )
|
2012-06-07 02:26:37 +02:00
|
|
|
{
|
2015-05-29 11:46:29 +02:00
|
|
|
bool function_need_ssl = (cur.request->function && cur.request->function->need_ssl);
|
|
|
|
|
2015-05-29 11:24:43 +02:00
|
|
|
if( cur.request->using_ssl )
|
|
|
|
{
|
2015-05-29 11:46:29 +02:00
|
|
|
if( !cur.session->puser && !function_need_ssl )
|
2015-05-29 11:24:43 +02:00
|
|
|
{
|
|
|
|
log << log3 << "App: this operation should NOT be used through SSL" << logend;
|
|
|
|
BaseUrlRedirect(config.use_ssl_redirect_code, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-29 11:46:29 +02:00
|
|
|
if( cur.session->puser || function_need_ssl )
|
2015-05-29 11:24:43 +02:00
|
|
|
{
|
|
|
|
log << log3 << "App: this operation should be used through SSL" << logend;
|
|
|
|
BaseUrlRedirect(config.use_ssl_redirect_code, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* use ssl for everyone
|
|
|
|
*/
|
|
|
|
if( !cur.request->using_ssl )
|
2012-09-24 22:31:01 +02:00
|
|
|
{
|
|
|
|
log << log3 << "App: this operation should be used through SSL" << logend;
|
|
|
|
BaseUrlRedirect(config.use_ssl_redirect_code, true);
|
|
|
|
}
|
2012-06-07 02:26:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-24 22:31:01 +02:00
|
|
|
if( cur.request->using_ssl )
|
|
|
|
{
|
|
|
|
log << log3 << "App: this operation should NOT be used through SSL" << logend;
|
|
|
|
BaseUrlRedirect(config.use_ssl_redirect_code, true);
|
|
|
|
}
|
2012-06-07 02:26:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-24 22:31:01 +02:00
|
|
|
|
|
|
|
|
2012-06-27 01:19:19 +02:00
|
|
|
void App::SetLocale()
|
|
|
|
{
|
|
|
|
size_t locale_id;
|
|
|
|
|
|
|
|
if( cur.session->puser )
|
|
|
|
{
|
|
|
|
locale_id = cur.session->puser->locale_id;
|
|
|
|
|
|
|
|
if( !TemplatesFunctions::locale.HasLanguage(locale_id) )
|
|
|
|
locale_id = config.locale_default_id;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
locale_id = config.locale_default_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplatesFunctions::locale.SetCurLang(locale_id);
|
|
|
|
}
|
|
|
|
|
2012-06-07 02:26:37 +02:00
|
|
|
|
2012-10-17 21:52:55 +02:00
|
|
|
|
|
|
|
bool App::CheckAccessFromPlugins()
|
|
|
|
{
|
|
|
|
PluginRes res = plugin.Call(WINIX_CHECK_PLUGIN_ACCESS);
|
|
|
|
|
|
|
|
if( res.res_false > 0 )
|
|
|
|
{
|
|
|
|
cur.request->status = WINIX_ERR_PERMISSION_DENIED;
|
|
|
|
log << log2 << "App: access prevented by a plugin" << logend;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
void App::ProcessRequestThrow()
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
ReadRequest();
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
// when BaseUrlRedirect() return true we didn't have to set everything in cur.request->Read()
|
|
|
|
// in the future cur.request->Read() can be split and at the beginning only environment variables will be read
|
2010-08-10 18:12:50 +02:00
|
|
|
// and then BaseUrlRedirect() will be called (for performance)
|
|
|
|
if( !BaseUrlRedirect() )
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
if( cur.request->env_request_uri.size() <= WINIX_URL_MAX_SIZE )
|
|
|
|
{
|
|
|
|
functions.Parse(); // parsing directories, files, functions and parameters
|
2018-06-19 15:52:08 +02:00
|
|
|
|
|
|
|
if( !cur.request->dir_tab.empty() )
|
|
|
|
{
|
2018-07-02 14:02:19 +02:00
|
|
|
cur.mount = system.mounts.CalcCurMount();
|
2018-06-19 15:52:08 +02:00
|
|
|
|
2019-03-19 19:08:09 +01:00
|
|
|
cur.session = session_manager.PrepareSession();
|
|
|
|
functions.CheckFunctionAndSymlink(); // here a function can be changed
|
|
|
|
cur.session = session_manager.CheckIfFunctionRequireSession();
|
2018-06-19 15:52:08 +02:00
|
|
|
SetLocale();
|
|
|
|
|
|
|
|
if( cur.session->new_session )
|
|
|
|
{
|
|
|
|
cur.session->plugin_data.Resize(plugin.Size());
|
|
|
|
plugin.Call(WINIX_SESSION_CREATED);
|
|
|
|
}
|
|
|
|
|
|
|
|
plugin.Call(WINIX_SESSION_CHANGED);
|
|
|
|
}
|
2014-10-09 22:44:56 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* IMPROVE ME
|
|
|
|
* it will not have the root directory set
|
|
|
|
* so as a response only a blank page is shown
|
|
|
|
* (root directory is set in funcions.Parse())
|
|
|
|
*
|
|
|
|
* IMPROVE ME
|
|
|
|
* we can add a better return code (http status):
|
|
|
|
* http://www.ietf.org/rfc/rfc2616.txt
|
|
|
|
* "A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle"
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
cur.request->status = WINIX_ERR_PERMISSION_DENIED;
|
|
|
|
log << log1 << "App: the URL is too long: " << cur.request->env_request_uri.size() << logend;
|
|
|
|
}
|
2013-11-14 21:59:23 +01:00
|
|
|
|
2018-06-19 15:52:08 +02:00
|
|
|
if( cur.request->dir_tab.empty() )
|
|
|
|
{
|
|
|
|
log << log1 << "App: there is no a root dir (dir_tab is empty), adding a root dir" << logend;
|
|
|
|
Item * root_dir = system.dirs.GetRootDir();
|
|
|
|
|
|
|
|
if( root_dir )
|
|
|
|
{
|
|
|
|
cur.request->dir_tab.push_back(root_dir);
|
|
|
|
cur.request->last_item = cur.request->dir_tab.back();
|
2018-07-02 14:02:19 +02:00
|
|
|
cur.mount = system.mounts.CalcCurMount();
|
2018-06-19 15:52:08 +02:00
|
|
|
}
|
2018-06-20 17:00:02 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
log << log1 << "App: oops, we do not have a root dir" << logend;
|
|
|
|
}
|
2018-06-19 15:52:08 +02:00
|
|
|
}
|
|
|
|
|
2012-09-24 22:31:01 +02:00
|
|
|
if( cur.mount->type != system.mounts.MountTypeStatic() )
|
|
|
|
Make();
|
2010-08-10 18:12:50 +02:00
|
|
|
}
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
SendAnswer();
|
2010-08-10 18:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
void App::ProcessRequest()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2012-02-17 06:19:24 +01:00
|
|
|
cur.request->RequestStarts();
|
2010-12-02 02:02:02 +01:00
|
|
|
system.load_avg.StartRequest();
|
|
|
|
log << log2 << config.log_delimiter << logend;
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
ProcessRequestThrow();
|
2019-03-19 19:08:09 +01:00
|
|
|
SaveSessionsIfNeeded();
|
2010-12-02 02:02:02 +01:00
|
|
|
|
|
|
|
system.load_avg.StopRequest();
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2011-01-23 15:15:30 +01:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
ClearAfterRequest();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-27 13:24:45 +01:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
void App::ClearAfterRequest()
|
|
|
|
{
|
2011-01-27 13:24:45 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
plugin.Call(WINIX_END_REQUEST);
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
log << log1 << "App: an exception from a plugin when clearing after a request" << logend;
|
2011-01-27 13:24:45 +01:00
|
|
|
}
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// simple operations which should not throw an exception
|
|
|
|
json_out_stream.Clear();
|
|
|
|
templates.ClearAfterRequest();
|
|
|
|
cur.request->Clear();
|
|
|
|
cur.session->ClearAfterRequest();
|
|
|
|
cur.session = session_manager.GetTmpSession();
|
|
|
|
output_8bit.clear();
|
|
|
|
compressed_output.clear();
|
|
|
|
html_filtered.clear();
|
|
|
|
aheader_name.clear();
|
|
|
|
aheader_value.clear();
|
2018-07-02 14:02:19 +02:00
|
|
|
cur.mount = system.mounts.GetEmptyMount();
|
|
|
|
system.mounts.pmount = cur.mount; // IMPROVE ME system.mounts.pmount will be removed
|
2013-12-04 02:21:57 +01:00
|
|
|
// send_data_buf doesn't have to be cleared and it is better to not clear it (optimizing)
|
|
|
|
|
|
|
|
log << logendrequest;
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
log << log1 << "App: an exception when clearing after a request" << logend;
|
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
|
2014-02-11 22:00:32 +01:00
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
void App::Start()
|
|
|
|
{
|
2010-12-02 02:02:02 +01:00
|
|
|
while( !synchro.was_stop_signal && FCGX_Accept_r(&fcgi_request) == 0 )
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2010-12-02 02:02:02 +01:00
|
|
|
Lock();
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-02-11 22:00:32 +01:00
|
|
|
if( synchro.was_stop_signal )
|
|
|
|
{
|
|
|
|
FCGX_Finish_r(&fcgi_request);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-12-02 02:02:02 +01:00
|
|
|
ProcessRequest();
|
2014-02-11 22:00:32 +01:00
|
|
|
}
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
Unlock();
|
2010-08-10 18:12:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::SaveSessionsIfNeeded()
|
|
|
|
{
|
2010-10-24 01:12:47 +02:00
|
|
|
time_t t = std::time(0);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
if( last_sessions_save + 86400 > t )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// saving once a day for safety
|
|
|
|
last_sessions_save = t;
|
|
|
|
session_manager.SaveSessions();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-14 21:59:23 +01:00
|
|
|
void App::CreateJSONAnswer()
|
|
|
|
{
|
|
|
|
Request & req = *cur.request;
|
|
|
|
json_out_stream.Clear();
|
|
|
|
|
|
|
|
if( !req.return_info_only )
|
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
json_out_stream << L"{\n\"out\": {\n";
|
2013-11-14 21:59:23 +01:00
|
|
|
|
2015-11-15 23:23:36 +01:00
|
|
|
auto i = req.out_streams.streams_map.begin();
|
|
|
|
bool is_first = true;
|
|
|
|
|
|
|
|
for( ; i != req.out_streams.streams_map.end() ; ++i)
|
2013-11-14 21:59:23 +01:00
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
if( !is_first )
|
|
|
|
{
|
|
|
|
json_out_stream << L",\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
json_out_stream << L"\"";
|
|
|
|
JSONescape(json_out_stream, i->first);
|
|
|
|
json_out_stream << L"\": \"";
|
|
|
|
JSONescape(json_out_stream, i->second->Str());
|
|
|
|
json_out_stream << L"\"";
|
|
|
|
is_first = false;
|
2013-11-14 21:59:23 +01:00
|
|
|
}
|
|
|
|
|
2015-11-15 23:23:36 +01:00
|
|
|
json_out_stream << L"}\n,\n\"info\": ";
|
2013-11-14 21:59:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if( req.info_serializer )
|
|
|
|
{
|
|
|
|
req.info_serializer->Serialize(req.info, json_out_stream, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
json_out_stream << L"{}";
|
|
|
|
log << log1 << "App: Request::info_serializer not defined" << logend;
|
|
|
|
}
|
|
|
|
|
|
|
|
log << log3 << "App: sending JSON answer";
|
|
|
|
|
|
|
|
if( !req.return_info_only )
|
|
|
|
json_out_stream << L"}\n";
|
|
|
|
else
|
|
|
|
log << " (Request::info only)";
|
|
|
|
|
|
|
|
log << logend;
|
|
|
|
}
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2014-11-25 13:02:22 +01:00
|
|
|
// !! IMPROVE ME change to a better name
|
2010-08-10 18:12:50 +02:00
|
|
|
void App::MakePage()
|
|
|
|
{
|
2011-06-24 22:53:21 +02:00
|
|
|
if( cur.request->page_generated || !cur.request->redirect_to.empty() || !cur.request->x_sendfile.empty() )
|
2010-08-10 18:12:50 +02:00
|
|
|
return;
|
|
|
|
|
2012-08-26 21:53:47 +02:00
|
|
|
templates.SetEzcParameters( cur.request->gen_trim_white,
|
|
|
|
cur.request->gen_skip_new_line,
|
|
|
|
cur.request->gen_use_special_chars);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2016-04-04 18:02:36 +02:00
|
|
|
templates.Generate();
|
2010-08-10 18:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-04 22:24:42 +02:00
|
|
|
void App::CheckPostRedirect()
|
|
|
|
{
|
|
|
|
if( cur.request->method == Request::post )
|
|
|
|
{
|
|
|
|
if( cur.request->IsParam(L"postredirect") )
|
|
|
|
{
|
|
|
|
cur.request->redirect_to = cur.request->ParamValue(L"postredirect");
|
|
|
|
cur.request->redirect_type = 303;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( cur.request->IsPostVar(L"postredirect") )
|
|
|
|
{
|
|
|
|
cur.request->redirect_to = cur.request->PostVar(L"postredirect");
|
|
|
|
cur.request->redirect_type = 303;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-25 13:02:22 +01:00
|
|
|
// !! IMPROVE ME change to a better name
|
|
|
|
// may ProcessRequest()? but probably it is already defined...
|
|
|
|
// this method needs some refactoring
|
2010-08-10 18:12:50 +02:00
|
|
|
void App::Make()
|
|
|
|
{
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->dir_tab.empty() )
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2011-09-07 00:46:15 +02:00
|
|
|
log << log1 << "App: there is no a root dir (dir_tab is empty)" << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-14 21:59:23 +01:00
|
|
|
if( cur.request->ParamValue(L"reqtype") == L"json" )
|
|
|
|
cur.request->return_json = true;
|
|
|
|
|
2012-10-27 09:44:26 +02:00
|
|
|
if( cur.session->ip_ban && cur.session->ip_ban->IsIPBanned() )
|
|
|
|
{
|
|
|
|
PT::Date date(cur.session->ip_ban->expires);
|
2018-11-21 12:03:53 +01:00
|
|
|
|
|
|
|
// IMPROVE ME there is no slog now
|
|
|
|
//slog << logerror << T("this_ip_is_banned_until") << ' ' << date << " UTC" << logend;
|
2012-10-27 09:44:26 +02:00
|
|
|
|
|
|
|
cur.request->status = WINIX_ERR_PERMISSION_DENIED;
|
|
|
|
}
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
// cur.request->status can be changed by function_parser
|
|
|
|
if( cur.request->status == WINIX_ERR_OK )
|
2010-10-24 01:51:44 +02:00
|
|
|
plugin.Call(WINIX_PREPARE_REQUEST);
|
|
|
|
|
2018-06-19 15:52:08 +02:00
|
|
|
// if( cur.request->status == WINIX_ERR_OK )
|
|
|
|
// functions.CheckFunctionAndSymlink();
|
2011-01-05 22:24:11 +01:00
|
|
|
|
2012-10-17 21:52:55 +02:00
|
|
|
CheckAccessFromPlugins();
|
|
|
|
|
2012-09-24 22:31:01 +02:00
|
|
|
// !! CHECK ME CheckFunctionAndSymlink can set redirect_to
|
|
|
|
// may it should be tested before calling CheckIfNeedSSLredirect?
|
|
|
|
CheckIfNeedSSLredirect();
|
|
|
|
|
|
|
|
if( !cur.request->redirect_to.empty() )
|
|
|
|
return;
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->status == WINIX_ERR_OK )
|
2011-01-05 22:24:11 +01:00
|
|
|
functions.MakeFunction();
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.session->spam_score > 0 )
|
|
|
|
log << log1 << "App: spam score: " << cur.session->spam_score << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->IsParam(L"noredirect") )
|
|
|
|
cur.request->redirect_to.clear();
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->status == WINIX_ERR_OK )
|
2010-10-24 01:51:44 +02:00
|
|
|
plugin.Call(WINIX_PROCESS_REQUEST);
|
|
|
|
|
2012-09-04 22:24:42 +02:00
|
|
|
CheckPostRedirect();
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( !cur.request->redirect_to.empty() )
|
2010-08-10 18:12:50 +02:00
|
|
|
return;
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->dir_tab.empty() )
|
2010-08-10 18:12:50 +02:00
|
|
|
{
|
2010-08-10 22:43:38 +02:00
|
|
|
log << log1 << "App: there is no a root dir (dir_tab is empty -- after calling a function)" << logend;
|
2010-08-10 18:12:50 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
plugin.Call(WINIX_CONTENT_MAKE);
|
|
|
|
MakePage();
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::LogEnvironmentVariables()
|
2011-09-07 00:46:15 +02:00
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
for(char ** e = fcgi_request.envp ; *e ; ++e )
|
|
|
|
log << log1 << "Env: " << *e << logend;
|
2011-09-07 00:46:15 +02:00
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
|
|
|
|
|
2018-04-25 21:48:47 +02:00
|
|
|
void App::LogEnvironmentHTTPVariables()
|
|
|
|
{
|
|
|
|
PT::Space::Table::iterator i = cur.request->headers_in.table.begin();
|
|
|
|
|
|
|
|
for( ; i != cur.request->headers_in.table.end() ; ++i)
|
|
|
|
{
|
|
|
|
log << log1 << "HTTP Env: " << i->first << "=";
|
|
|
|
|
|
|
|
if( i->second.size() == 1 )
|
|
|
|
log << i->second[0] << logend;
|
|
|
|
else
|
|
|
|
log << "(incorrect value table size, should be one but is " << i->second.size() << ")" << logend;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
/*
|
|
|
|
* reading the request (without GET parameters in the URL)
|
|
|
|
*/
|
2010-08-12 21:10:12 +02:00
|
|
|
void App::ReadRequest()
|
|
|
|
{
|
|
|
|
ReadEnvVariables();
|
2014-10-09 22:44:56 +02:00
|
|
|
ReadEnvRemoteIP();
|
2010-08-12 21:10:12 +02:00
|
|
|
CheckRequestMethod();
|
2011-09-07 00:46:15 +02:00
|
|
|
CheckSSL();
|
2012-04-22 20:23:44 +02:00
|
|
|
SetSubdomain();
|
2010-08-12 21:10:12 +02:00
|
|
|
|
|
|
|
LogAccess();
|
2018-04-25 21:48:47 +02:00
|
|
|
ReadEnvHTTPVariables();
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
ReadPostVars();
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
cookie_parser.Parse(cur.request->env_http_cookie, cur.request->cookie_tab);
|
2011-04-02 02:10:16 +02:00
|
|
|
accept_encoding_parser.ParseAndLog(cur.request->env_http_accept_encoding);
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
if( config.log_env_variables )
|
|
|
|
LogEnvironmentVariables();
|
|
|
|
|
2018-04-25 21:48:47 +02:00
|
|
|
if( config.log_env_http_variables )
|
|
|
|
LogEnvironmentHTTPVariables();
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
CheckIE();
|
|
|
|
CheckKonqueror();
|
|
|
|
|
2011-09-07 00:46:15 +02:00
|
|
|
if( cur.request->using_ssl )
|
2012-10-27 09:44:26 +02:00
|
|
|
log << log3 << "App: connection secure through SSL" << logend;
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
void App::SetEnv(const char * name, std::wstring & env)
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
const char * v = FCGX_GetParam(name, fcgi_request.envp);
|
2010-08-12 21:10:12 +02:00
|
|
|
|
|
|
|
if( v )
|
2014-10-09 22:44:56 +02:00
|
|
|
{
|
|
|
|
PT::UTF8ToWide(v, env);
|
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
void App::ReadEnvVariables()
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
SetEnv("REQUEST_METHOD", cur.request->env_request_method);
|
|
|
|
SetEnv("REQUEST_URI", cur.request->env_request_uri);
|
|
|
|
SetEnv("FCGI_ROLE", cur.request->env_fcgi_role);
|
|
|
|
SetEnv("CONTENT_TYPE", cur.request->env_content_type);
|
|
|
|
SetEnv("HTTPS", cur.request->env_https);
|
2018-04-25 21:48:47 +02:00
|
|
|
|
|
|
|
SetEnv("HTTP_HOST", cur.request->env_http_host);
|
|
|
|
SetEnv("HTTP_USER_AGENT", cur.request->env_http_user_agent);
|
|
|
|
SetEnv("HTTP_COOKIE", cur.request->env_http_cookie);
|
|
|
|
SetEnv("HTTP_ACCEPT_ENCODING", cur.request->env_http_accept_encoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// reading from fastcgi env
|
|
|
|
void App::ReadEnvHTTPVariables()
|
|
|
|
{
|
|
|
|
const char http_prefix[] = "HTTP_";
|
|
|
|
size_t http_prefix_len = sizeof(http_prefix) / sizeof(char) - 1; // 1 means terminating null character
|
|
|
|
size_t http_headers_saved = 0;
|
|
|
|
|
|
|
|
for(char ** e = fcgi_request.envp ; *e && http_headers_saved < Request::MAX_INPUT_HEADERS ; ++e)
|
|
|
|
{
|
|
|
|
char * env = *e;
|
|
|
|
|
2018-11-01 01:46:44 +01:00
|
|
|
if( PT::IsSubStringNoCasep("HTTP_", env) )
|
2018-04-25 21:48:47 +02:00
|
|
|
{
|
|
|
|
env += http_prefix_len;
|
|
|
|
|
|
|
|
// cookies we have in a different table
|
2018-11-01 01:46:44 +01:00
|
|
|
if( !PT::IsSubStringNoCasep("COOKIE=", env) )
|
2018-04-25 21:48:47 +02:00
|
|
|
{
|
|
|
|
if( SaveEnvHTTPVariable(env) )
|
|
|
|
{
|
|
|
|
http_headers_saved += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( http_headers_saved == Request::MAX_INPUT_HEADERS )
|
|
|
|
{
|
|
|
|
log << log4 << "App: the maximum number of HTTP headers has been reached, skipping the rest" << logend;
|
|
|
|
}
|
2014-10-09 22:44:56 +02:00
|
|
|
}
|
|
|
|
|
2012-10-27 09:44:26 +02:00
|
|
|
|
2018-04-25 21:48:47 +02:00
|
|
|
/*
|
|
|
|
* headers in fcgi are in the form of name=value
|
|
|
|
*/
|
|
|
|
bool App::SaveEnvHTTPVariable(const char * env)
|
|
|
|
{
|
|
|
|
// CHECK ME may move to a better place? Request::INPUT_HEADER_VALUE_MAX_LENGTH is a high value
|
|
|
|
char header_name[Request::INPUT_HEADER_NAME_MAX_LENGTH + 1];
|
|
|
|
char header_value[Request::INPUT_HEADER_VALUE_MAX_LENGTH + 1];
|
|
|
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
for( ; env[i] != 0 && env[i] != '=' && i < Request::INPUT_HEADER_NAME_MAX_LENGTH ; ++i)
|
|
|
|
{
|
2018-05-25 19:22:12 +02:00
|
|
|
header_name[i] = PT::ToLower(env[i]);
|
2018-04-25 21:48:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
header_name[i] = 0;
|
|
|
|
|
|
|
|
if( env[i] != '=' )
|
|
|
|
{
|
|
|
|
// too long header name, skipping
|
|
|
|
log << log4 << "App: skipped HTTP header \"" << env << "\" because the header name is too long" << logend;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
i += 1; // skipping '=' character
|
|
|
|
size_t h = 0;
|
|
|
|
|
|
|
|
for( ; env[i] != 0 && h < Request::INPUT_HEADER_VALUE_MAX_LENGTH ; ++i, ++h)
|
|
|
|
{
|
|
|
|
header_value[h] = env[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
header_value[h] = 0;
|
|
|
|
|
|
|
|
if( env[i] != 0 )
|
|
|
|
{
|
|
|
|
// too long header value, skipping
|
|
|
|
log << log4 << "App: skipped HTTP header \"" << env << "\" because the header value is too long" << logend;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PT::UTF8ToWide(header_name, http_header);
|
|
|
|
|
|
|
|
std::wstring & inserted_header = cur.request->headers_in.Add(http_header, L"", true);
|
|
|
|
PT::UTF8ToWide(header_value, inserted_header);
|
|
|
|
http_header.clear();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
|
|
|
void App::ReadEnvRemoteIP()
|
|
|
|
{
|
2018-05-01 13:22:55 +02:00
|
|
|
const char * v = nullptr;
|
|
|
|
|
|
|
|
if( config.check_proxy_ip_header )
|
|
|
|
{
|
|
|
|
http_header = L"HTTP_";
|
|
|
|
http_header += config.proxy_ip_header;
|
2018-05-25 19:22:12 +02:00
|
|
|
PT::ToUpper(http_header);
|
2018-05-01 13:22:55 +02:00
|
|
|
|
|
|
|
PT::WideToUTF8(http_header, http_header_8bit);
|
|
|
|
v = FCGX_GetParam(http_header_8bit.c_str(), fcgi_request.envp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
v = FCGX_GetParam("REMOTE_ADDR", fcgi_request.envp);
|
|
|
|
}
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( v )
|
|
|
|
{
|
|
|
|
cur.request->ip = (int)inet_addr(v);
|
2018-05-01 13:22:55 +02:00
|
|
|
PT::UTF8ToWide(v, cur.request->ip_str);
|
2014-10-09 22:44:56 +02:00
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
void App::CheckRequestMethod()
|
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
cur.request->method = Request::unknown_method;
|
2014-10-09 22:44:56 +02:00
|
|
|
|
|
|
|
if( !cur.request->env_request_method.empty() )
|
|
|
|
{
|
2018-05-25 19:22:12 +02:00
|
|
|
if( PT::ToLower(cur.request->env_request_method[0]) == 'g' )
|
2014-10-09 22:44:56 +02:00
|
|
|
cur.request->method = Request::get;
|
|
|
|
else
|
2018-05-25 19:22:12 +02:00
|
|
|
if( PT::ToLower(cur.request->env_request_method[0]) == 'p' )
|
2014-10-09 22:44:56 +02:00
|
|
|
cur.request->method = Request::post;
|
|
|
|
else
|
2018-05-25 19:22:12 +02:00
|
|
|
if( PT::ToLower(cur.request->env_request_method[0]) == 'h' )
|
2014-10-09 22:44:56 +02:00
|
|
|
cur.request->method = Request::head;
|
2018-04-25 21:48:47 +02:00
|
|
|
else
|
2018-05-25 19:22:12 +02:00
|
|
|
if( PT::ToLower(cur.request->env_request_method[0]) == 'd' )
|
2018-04-25 21:48:47 +02:00
|
|
|
cur.request->method = Request::delete_;
|
2014-10-09 22:44:56 +02:00
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-09-07 00:46:15 +02:00
|
|
|
void App::CheckSSL()
|
|
|
|
{
|
2012-06-07 02:26:37 +02:00
|
|
|
// !! CHECK ME
|
2011-09-07 00:46:15 +02:00
|
|
|
// value "on" exists in lighttpd server
|
|
|
|
// make sure that for other servers is "on" too
|
|
|
|
|
2018-01-01 01:14:02 +01:00
|
|
|
if( config.assume_connection_is_through_ssl )
|
|
|
|
cur.request->using_ssl = true;
|
|
|
|
else
|
2018-05-25 19:22:12 +02:00
|
|
|
if( PT::EqualNoCase(cur.request->env_https.c_str(), L"on") )
|
2011-09-07 00:46:15 +02:00
|
|
|
cur.request->using_ssl = true;
|
|
|
|
}
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2012-04-22 20:23:44 +02:00
|
|
|
void App::SetSubdomain()
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
CreateSubdomain(config.base_url.c_str(), cur.request->env_http_host.c_str(), cur.request->subdomain);
|
2012-04-22 20:23:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
void App::LogAccess()
|
|
|
|
{
|
2012-09-06 19:50:14 +02:00
|
|
|
log << log1;
|
2018-11-21 12:03:53 +01:00
|
|
|
log.PrintDate(cur.request->start_date);
|
2012-09-06 19:50:14 +02:00
|
|
|
|
|
|
|
log << ' '
|
2018-05-01 13:22:55 +02:00
|
|
|
<< cur.request->ip_str << ' '
|
2011-01-23 15:15:30 +01:00
|
|
|
<< cur.request->env_request_method << ' '
|
|
|
|
<< cur.request->env_http_host
|
|
|
|
<< cur.request->env_request_uri << ' '
|
|
|
|
<< cur.request->env_http_user_agent << logend;
|
2012-06-07 02:26:37 +02:00
|
|
|
|
|
|
|
if( !cur.request->subdomain.empty() )
|
|
|
|
log << log3 << "Subdomain: " << cur.request->subdomain << logend;
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-04-26 20:56:31 +02:00
|
|
|
void App::ReadPostJson()
|
|
|
|
{
|
|
|
|
char buffer[1024];
|
|
|
|
const int buffer_len = sizeof(buffer) / sizeof(char) - 1;
|
|
|
|
int read_len;
|
|
|
|
|
|
|
|
post_json_parser.SetSpace(cur.request->post_in);
|
|
|
|
post_buffer.clear();
|
|
|
|
post_buffer.reserve(1024 * 1024 * 5); // IMPROVEME add to config?
|
|
|
|
|
|
|
|
cur.request->is_postin_used = true;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
// IMPROVE ME
|
|
|
|
// we can read to PT::TextBuffer and make a PT::JSONToSpaceParser::Parse(PT::TextBuffer &) method
|
|
|
|
read_len = FCGX_GetStr(buffer, buffer_len, fcgi_request.in);
|
|
|
|
|
|
|
|
if( read_len > 0 )
|
|
|
|
post_buffer.append(buffer, read_len);
|
|
|
|
}
|
|
|
|
while( read_len == buffer_len );
|
|
|
|
|
2019-03-25 01:51:51 +01:00
|
|
|
if( !post_buffer.empty() )
|
|
|
|
{
|
|
|
|
PT::JSONToSpaceParser::Status status = post_json_parser.ParseString(post_buffer.c_str());
|
|
|
|
post_buffer.clear();
|
2018-04-26 20:56:31 +02:00
|
|
|
|
2019-03-25 01:51:51 +01:00
|
|
|
if( status != PT::JSONToSpaceParser::ok )
|
|
|
|
{
|
|
|
|
log << log1 << "App: cannot parse the input stream as a JSON object, status: " << (int)status << logend;
|
|
|
|
cur.request->post_in.Clear();
|
|
|
|
// return an error (http error of some kind?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2018-04-26 20:56:31 +02:00
|
|
|
{
|
2019-03-25 01:51:51 +01:00
|
|
|
log << log3 << "App: input body empty (skipping parsing)" << logend;
|
2018-04-26 20:56:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
void App::ReadPostVars()
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2018-04-26 20:56:31 +02:00
|
|
|
// CHECKME
|
|
|
|
// what about errors during parsing input?
|
|
|
|
|
|
|
|
if( cur.request->method == Request::post || cur.request->method == Request::delete_ )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2018-11-01 01:46:44 +01:00
|
|
|
if( PT::IsSubStringNoCase(L"multipart/form-data", cur.request->env_content_type.c_str()) )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2011-09-07 00:46:15 +02:00
|
|
|
log << log3 << "App: post content type: multipart/form-data" << logend;
|
2011-01-23 15:15:30 +01:00
|
|
|
post_multi_parser.Parse(fcgi_request.in, cur.request->post_tab, cur.request->post_file_tab);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
else
|
2018-11-01 01:46:44 +01:00
|
|
|
if( PT::IsSubStringNoCase(L"application/json", cur.request->env_content_type.c_str()) )
|
2018-04-26 20:56:31 +02:00
|
|
|
{
|
|
|
|
log << log3 << "App: post content type: application/json" << logend;
|
|
|
|
ReadPostJson();
|
|
|
|
}
|
|
|
|
else
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2018-04-26 20:56:31 +02:00
|
|
|
// IMPROVE ME may to check a correct content-type header?
|
2011-01-23 15:15:30 +01:00
|
|
|
post_parser.Parse(fcgi_request.in, cur.request->post_tab);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void App::CheckIE()
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
size_t msie = cur.request->env_http_user_agent.find(L"MSIE");
|
|
|
|
cur.request->browser_msie = (msie != std::wstring::npos);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void App::CheckKonqueror()
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
size_t kon = cur.request->env_http_user_agent.find(L"Konqueror");
|
|
|
|
cur.request->browser_konqueror = (kon != std::wstring::npos);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void App::PrepareSessionCookie()
|
|
|
|
{
|
2011-01-23 15:15:30 +01:00
|
|
|
if( !cur.session || cur.session->id==0 )
|
2010-08-12 21:10:12 +02:00
|
|
|
return;
|
|
|
|
|
2014-11-22 16:30:56 +01:00
|
|
|
if( config.session_cookie_encode )
|
|
|
|
{
|
|
|
|
if( !session_manager.EncodeSessionId(cur.session->id, cur.session->id_index, cookie_id_string) )
|
|
|
|
Toa(cur.session->id, cookie_id_string);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Toa(cur.session->id, cookie_id_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( !cur.session->puser || !cur.session->remember_me )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2014-11-22 16:30:56 +01:00
|
|
|
cur.request->AddCookie(config.http_session_id_name, cookie_id_string);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-05-27 01:04:49 +02:00
|
|
|
PT::Date expires = cur.request->start_time + config.session_remember_max_idle;
|
2014-11-22 16:30:56 +01:00
|
|
|
cur.request->AddCookie(config.http_session_id_name, cookie_id_string, expires);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-22 16:30:56 +01:00
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
bool App::AddHeader(const wchar_t * name, const wchar_t * value)
|
|
|
|
{
|
|
|
|
if( !cur.request->out_headers.GetValue(name) )
|
|
|
|
{
|
|
|
|
cur.request->out_headers.Add(name, value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool App::AddHeader(const std::wstring & name, const std::wstring & value)
|
|
|
|
{
|
|
|
|
if( !cur.request->out_headers.GetValue(name) )
|
|
|
|
{
|
|
|
|
cur.request->out_headers.Add(name, value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool App::AddHeader(const wchar_t * name, const PT::WTextStream & value)
|
|
|
|
{
|
|
|
|
if( !cur.request->out_headers.GetValue(name) )
|
|
|
|
{
|
|
|
|
cur.request->out_headers.Add(name, value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool App::AddHeader(const std::wstring & name, const PT::WTextStream & value)
|
|
|
|
{
|
|
|
|
if( !cur.request->out_headers.GetValue(name) )
|
|
|
|
{
|
|
|
|
cur.request->out_headers.Add(name, value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
bool App::PrepareHeadersStaticCreateResource(PT::WTextStream & out_path)
|
2011-09-07 00:46:15 +02:00
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
Item * dir = system.dirs.GetDir(system.mounts.pmount->dir_id);
|
|
|
|
|
|
|
|
if( !dir )
|
|
|
|
{
|
|
|
|
log << log1 << "App: cannot find the mount directory" << logend;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t how_many_dirs = system.dirs.DirLevel(dir->id);
|
2014-10-09 22:44:56 +02:00
|
|
|
const wchar_t * path = SkipDirs(cur.request->env_request_uri.c_str(), how_many_dirs);
|
2011-09-07 00:46:15 +02:00
|
|
|
|
|
|
|
// the path begins with a slash only if how_many_dirs is zero
|
|
|
|
while( *path == '/' )
|
|
|
|
path += 1;
|
|
|
|
|
|
|
|
while( path[i]!=0 && path[i]!='?' && path[i]!='#' )
|
|
|
|
++i;
|
|
|
|
|
|
|
|
if( i > 0 )
|
2013-11-29 22:39:23 +01:00
|
|
|
out_path.write(path, i);
|
2011-09-07 00:46:15 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::PrepareHeadersStatic()
|
2011-06-15 01:45:42 +02:00
|
|
|
{
|
|
|
|
if( PathHasUpDir(cur.request->env_request_uri) )
|
|
|
|
{
|
|
|
|
log << log1 << "App: incorrect path for a static file" << logend;
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersForbidden();
|
2011-06-15 01:45:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::wstring & index_str = system.mounts.pmount->FirstArg(system.mounts.MountParStatic());
|
|
|
|
size_t index = Toi(index_str);
|
|
|
|
|
|
|
|
if( index >= config.static_dirs.size() )
|
|
|
|
{
|
|
|
|
log << log1 << "App: static dir with index " << index << " is not defined in the config" << logend;
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersForbidden();
|
2011-06-15 01:45:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
PT::WTextStream path;
|
|
|
|
path << config.static_dirs[index] << L"/";
|
2011-06-15 01:45:42 +02:00
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
if( !PrepareHeadersStaticCreateResource(path) )
|
2011-06-15 01:45:42 +02:00
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersForbidden();
|
2011-06-15 01:45:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"200 OK");
|
2011-06-15 01:45:42 +02:00
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
if( AddHeader(config.http_header_send_file, path) )
|
|
|
|
log << log2 << "App: sending a file from a static mountpoint: " << path << logend;
|
|
|
|
}
|
2011-06-15 01:45:42 +02:00
|
|
|
|
2013-03-26 01:04:01 +01:00
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::PrepareHeaderContentType()
|
2011-12-17 22:59:22 +01:00
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
std::wstring * value = 0;
|
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
if( !cur.request->out_headers.GetValue(L"Content-Type") )
|
2011-12-17 22:59:22 +01:00
|
|
|
{
|
2013-12-19 18:19:47 +01:00
|
|
|
if( cur.request->return_json )
|
2013-03-26 01:04:01 +01:00
|
|
|
{
|
2013-12-19 18:19:47 +01:00
|
|
|
value = &cur.request->out_headers.Add(L"Content-Type", L"application/json");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch( config.content_type_header )
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
value = &cur.request->out_headers.Add(L"Content-Type", L"application/xhtml+xml");
|
|
|
|
break;
|
2013-03-26 01:04:01 +01:00
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
case 2:
|
|
|
|
value = &cur.request->out_headers.Add(L"Content-Type", L"application/xml");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
value = &cur.request->out_headers.Add(L"Content-Type", L"text/html");
|
|
|
|
}
|
2013-03-26 01:04:01 +01:00
|
|
|
}
|
2011-12-17 22:59:22 +01:00
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( value )
|
2013-12-19 18:19:47 +01:00
|
|
|
*value += L"; charset=UTF-8";
|
|
|
|
}
|
2011-12-17 22:59:22 +01:00
|
|
|
}
|
|
|
|
|
2011-06-15 01:45:42 +02:00
|
|
|
|
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::PrepareHeadersForbidden()
|
2011-06-15 01:45:42 +02:00
|
|
|
{
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"403 Forbidden");
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeaderContentType();
|
2011-06-15 01:45:42 +02:00
|
|
|
}
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::PrepareHeadersRedirect()
|
2011-07-07 19:02:14 +02:00
|
|
|
{
|
|
|
|
switch(cur.request->redirect_type)
|
|
|
|
{
|
|
|
|
case 300:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"300 Multiple Choices");
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 301:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"301 Moved Permanently");
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 302:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"302 Found");
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 307:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"307 Temporary Redirect");
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 303:
|
|
|
|
default:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"303 See Other");
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Location", cur.request->redirect_to);
|
2013-11-29 22:39:23 +01:00
|
|
|
log << log2 << "App: redirect to: " << cur.request->redirect_to << logend;
|
2011-07-07 19:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::PrepareHeadersSendFile()
|
2011-07-07 19:02:14 +02:00
|
|
|
{
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"200 OK");
|
2011-07-07 19:02:14 +02:00
|
|
|
|
2013-12-19 18:19:47 +01:00
|
|
|
if( AddHeader(config.http_header_send_file, cur.request->x_sendfile) )
|
|
|
|
log << log2 << "App: sending file: " << cur.request->x_sendfile << logend;
|
2011-07-07 19:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::PrepareHeadersCompression(int compress_encoding)
|
2011-07-07 19:02:14 +02:00
|
|
|
{
|
|
|
|
if( compress_encoding == 0 || compress_encoding == 1 )
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Content-Encoding", L"deflate");
|
2011-07-07 19:02:14 +02:00
|
|
|
else
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Content-Encoding", L"gzip");
|
2011-07-07 19:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
void App::PrepareHeadersNormal(Header header, size_t output_size)
|
2011-07-07 19:02:14 +02:00
|
|
|
{
|
|
|
|
switch( header )
|
|
|
|
{
|
|
|
|
case h_404:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"404 Not Found");
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeaderContentType();
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case h_403:
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersForbidden();
|
2011-07-07 19:02:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Status", L"200 OK");
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeaderContentType();
|
|
|
|
}
|
2013-12-04 02:21:57 +01:00
|
|
|
|
|
|
|
if( output_size != static_cast<size_t>(-1) )
|
2013-12-19 18:19:47 +01:00
|
|
|
{
|
|
|
|
PT::WTextStream buf;
|
|
|
|
buf << output_size;
|
|
|
|
AddHeader(L"Content-Length", buf);
|
|
|
|
}
|
2013-11-29 22:39:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// we can improve SendHeaders and SendCookies methods by checking
|
|
|
|
// whether there is a new line character in either a name or a value
|
|
|
|
// and if such character exists and is being sent to the client it breaks the http headers and content
|
|
|
|
// and if compression is enabled the client's browser will not be able to decompress the stream
|
|
|
|
void App::SendHeaders()
|
|
|
|
{
|
2018-01-06 19:12:53 +01:00
|
|
|
PT::Space::Table::iterator i;
|
2013-11-29 22:39:23 +01:00
|
|
|
PT::Space & headers = cur.request->out_headers;
|
|
|
|
|
|
|
|
plugin.Call(WINIX_PREPARE_TO_SEND_HTTP_HEADERS, &headers);
|
2011-07-07 19:02:14 +02:00
|
|
|
|
2018-01-06 19:12:53 +01:00
|
|
|
for(i=headers.table.begin() ; i != headers.table.end() ; ++i)
|
2013-11-29 22:39:23 +01:00
|
|
|
{
|
2018-01-06 19:12:53 +01:00
|
|
|
if( i->second.size() == 1 )
|
|
|
|
{
|
|
|
|
PT::WideToUTF8(i->first, aheader_name);
|
|
|
|
PT::WideToUTF8(i->second[0], aheader_value);
|
2013-11-29 22:39:23 +01:00
|
|
|
|
2018-01-06 19:12:53 +01:00
|
|
|
FCGX_PutS(aheader_name.c_str(), fcgi_request.out);
|
|
|
|
FCGX_PutS(": ", fcgi_request.out);
|
|
|
|
FCGX_PutS(aheader_value.c_str(), fcgi_request.out);
|
|
|
|
FCGX_PutS("\r\n", fcgi_request.out);
|
2013-11-29 22:39:23 +01:00
|
|
|
|
2018-01-06 19:12:53 +01:00
|
|
|
if( config.log_http_answer_headers )
|
|
|
|
log << log1 << "HTTP Header: " << aheader_name << ": " << aheader_value << logend;
|
|
|
|
}
|
2011-07-07 19:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
2013-11-29 22:39:23 +01:00
|
|
|
void App::SendCookies()
|
|
|
|
{
|
2018-01-06 19:12:53 +01:00
|
|
|
PT::Space::Table::iterator i;
|
2013-11-29 22:39:23 +01:00
|
|
|
PT::Space & cookies = cur.request->out_cookies;
|
|
|
|
|
|
|
|
plugin.Call(WINIX_PREPARE_TO_SEND_HTTP_COOKIES, &cookies);
|
|
|
|
|
2018-01-06 19:12:53 +01:00
|
|
|
for(i=cookies.table.begin() ; i != cookies.table.end() ; ++i)
|
2013-11-29 22:39:23 +01:00
|
|
|
{
|
2018-01-06 19:12:53 +01:00
|
|
|
if( i->second.size() == 1 )
|
|
|
|
{
|
|
|
|
PT::WideToUTF8(i->first, aheader_name);
|
|
|
|
PT::WideToUTF8(i->second[0], aheader_value);
|
2013-11-29 22:39:23 +01:00
|
|
|
|
2018-01-06 19:12:53 +01:00
|
|
|
FCGX_PutS("Set-Cookie: ", fcgi_request.out);
|
|
|
|
FCGX_PutS(aheader_name.c_str(), fcgi_request.out);
|
|
|
|
FCGX_PutS("=", fcgi_request.out);
|
|
|
|
FCGX_PutS(aheader_value.c_str(), fcgi_request.out);
|
|
|
|
FCGX_PutS("\r\n", fcgi_request.out);
|
2013-11-29 22:39:23 +01:00
|
|
|
|
2018-01-06 19:12:53 +01:00
|
|
|
if( config.log_http_answer_headers )
|
|
|
|
log << log1 << "HTTP Header: Set-Cookie: " << aheader_name << "=" << aheader_value << logend;
|
|
|
|
}
|
2013-11-29 22:39:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:02:14 +02:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
void App::PrepareHeaders(bool compressing, int compress_encoding, Header header, size_t output_size)
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
|
|
|
PrepareSessionCookie();
|
|
|
|
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->send_as_attachment )
|
2013-12-19 18:19:47 +01:00
|
|
|
AddHeader(L"Content-Disposition", L"attachment");
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2019-02-19 11:36:20 +01:00
|
|
|
if( !cur.request->redirect_to.empty() && !cur.request->return_json )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersRedirect();
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
else
|
2011-06-15 01:45:42 +02:00
|
|
|
if( system.mounts.pmount->type == system.mounts.MountTypeStatic() )
|
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersStatic();
|
2011-06-15 01:45:42 +02:00
|
|
|
}
|
|
|
|
else
|
2011-01-23 15:15:30 +01:00
|
|
|
if( !cur.request->x_sendfile.empty() )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersSendFile();
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
PrepareHeadersNormal(header, output_size);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
2011-04-02 02:10:16 +02:00
|
|
|
if( compressing )
|
2013-11-29 22:39:23 +01:00
|
|
|
PrepareHeadersCompression(compress_encoding);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-19 11:36:20 +01:00
|
|
|
void App::PrepareStandardJSONFields()
|
|
|
|
{
|
|
|
|
PT::Space & info = cur.request->info;
|
|
|
|
|
|
|
|
if( !info.GetFirstValue(L"status") )
|
|
|
|
{
|
|
|
|
info.Add(L"status", cur.request->status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !cur.request->redirect_to.empty() && !info.GetFirstValue(L"redirect_to") )
|
|
|
|
{
|
|
|
|
info.Add(L"redirect_to", cur.request->redirect_to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
void App::FilterContent()
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
Request & req = *cur.request;
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2015-11-15 23:23:36 +01:00
|
|
|
bool filter_main_stream = false;
|
|
|
|
bool filter_json = false;
|
2010-08-12 21:10:12 +02:00
|
|
|
|
2016-04-04 18:02:36 +02:00
|
|
|
if( config.html_filter && !req.send_bin_stream )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
if( req.return_json )
|
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
if( !req.return_info_only && req.out_streams_use_html_filter )
|
2013-12-04 02:21:57 +01:00
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
filter_json = true;
|
2013-12-04 02:21:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
if( req.out_main_stream_use_html_filter )
|
|
|
|
filter_main_stream = true;
|
2013-12-04 02:21:57 +01:00
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
2015-11-15 23:23:36 +01:00
|
|
|
if( filter_main_stream )
|
|
|
|
{
|
|
|
|
// !! IMPROVE ME may some kind of html_filtered.reserve() here? (optimization)
|
|
|
|
TemplatesFunctions::html_filter.Filter(req.out_main_stream.Str(), html_filtered);
|
|
|
|
req.out_main_stream.Str(std::move(html_filtered)); // !! IMPROVE ME we do not have Str(&&) method
|
2016-07-13 15:13:56 +02:00
|
|
|
log << log3 << "App: html in the main stream has been filtered" << logend;
|
2015-11-15 23:23:36 +01:00
|
|
|
}
|
2013-11-14 21:59:23 +01:00
|
|
|
|
2015-11-15 23:23:36 +01:00
|
|
|
if( filter_json )
|
2013-12-04 02:21:57 +01:00
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
for(auto i = req.out_streams.streams_map.begin() ; i != req.out_streams.streams_map.end() ; ++i)
|
2013-12-04 02:21:57 +01:00
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
HtmlTextStream & stream = *i->second;
|
2013-12-04 02:21:57 +01:00
|
|
|
// !! IMPROVE ME may some kind of html_filtered.reserve() here? (optimization)
|
2015-11-15 23:23:36 +01:00
|
|
|
TemplatesFunctions::html_filter.Filter(stream.Str(), html_filtered);
|
|
|
|
stream.Str(std::move(html_filtered));
|
2013-12-04 02:21:57 +01:00
|
|
|
}
|
2016-07-13 15:13:56 +02:00
|
|
|
|
|
|
|
log << log3 << "App: html in json out streams have been filtered" << logend;
|
2013-12-04 02:21:57 +01:00
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-09-11 07:19:45 +02:00
|
|
|
|
2011-04-02 02:10:16 +02:00
|
|
|
int App::SelectDeflateVersion()
|
|
|
|
{
|
|
|
|
if( cur.request->browser_msie )
|
|
|
|
return 0; // raw deflate
|
|
|
|
else
|
|
|
|
return 1; // deflate
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
|
2011-04-02 02:10:16 +02:00
|
|
|
void App::SelectCompression(size_t source_len, bool & compression_allowed, int & compression_encoding)
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2011-04-02 02:10:16 +02:00
|
|
|
compression_allowed = false;
|
|
|
|
compression_encoding = 0;
|
|
|
|
|
|
|
|
if( config.compression &&
|
|
|
|
cur.request->redirect_to.empty() &&
|
|
|
|
cur.request->x_sendfile.empty() &&
|
|
|
|
!cur.request->browser_konqueror && /* !! sprawdzic czy Konqueror bedzie obslugiwal raw deflate */
|
|
|
|
source_len >= config.compression_page_min_size )
|
|
|
|
{
|
|
|
|
if( config.compression_encoding == 1 || config.compression_encoding == 10 )
|
|
|
|
{
|
|
|
|
if( accept_encoding_parser.AcceptDeflate() )
|
|
|
|
{
|
|
|
|
compression_allowed = true;
|
|
|
|
compression_encoding = SelectDeflateVersion();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( config.compression_encoding == 10 && accept_encoding_parser.AcceptGzip() )
|
|
|
|
{
|
|
|
|
compression_allowed = true;
|
|
|
|
compression_encoding = 2; // gzip
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if( config.compression_encoding == 2 || config.compression_encoding == 20 )
|
|
|
|
{
|
|
|
|
if( accept_encoding_parser.AcceptGzip() )
|
|
|
|
{
|
|
|
|
compression_allowed = true;
|
|
|
|
compression_encoding = 2; // gzip
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( config.compression_encoding == 20 && accept_encoding_parser.AcceptDeflate() )
|
|
|
|
{
|
|
|
|
compression_allowed = true;
|
|
|
|
compression_encoding = SelectDeflateVersion();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-02 02:10:16 +02:00
|
|
|
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
bool App::CanSendContent()
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2019-02-19 11:36:20 +01:00
|
|
|
if( !cur.request->x_sendfile.empty() )
|
|
|
|
{
|
|
|
|
// if there is a file to send then we do not send a content
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cur.request->return_json )
|
|
|
|
{
|
|
|
|
// if there is a redirect flag then it will be put to info struct
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !cur.request->redirect_to.empty() )
|
|
|
|
{
|
|
|
|
// if there is a redirect and no json is requred then we do not send the content
|
2010-08-12 21:10:12 +02:00
|
|
|
return false;
|
2019-02-19 11:36:20 +01:00
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
we don't have to check the HEAD method
|
|
|
|
the server (lighttpd) doesn't send the body of its own
|
|
|
|
*/
|
2011-01-23 15:15:30 +01:00
|
|
|
if( cur.request->method == Request::head )
|
2010-08-12 21:10:12 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
App::Header App::GetHTTPStatusCode()
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
Error status = cur.request->status;
|
|
|
|
Header header = h_200;
|
2010-08-12 21:10:12 +02:00
|
|
|
|
|
|
|
if( status == WINIX_ERR_NO_ITEM || status == WINIX_ERR_NO_FUNCTION || status == WINIX_ERR_UNKNOWN_PARAM )
|
2013-03-26 01:04:01 +01:00
|
|
|
{
|
2010-08-12 21:10:12 +02:00
|
|
|
header = h_404;
|
2013-03-26 01:04:01 +01:00
|
|
|
log << log2 << "App: http response: 404 Not Found" << logend;
|
|
|
|
}
|
2010-08-12 21:10:12 +02:00
|
|
|
|
|
|
|
if( status == WINIX_ERR_PERMISSION_DENIED || status == WINIX_ERR_CANT_CHANGE_USER || status == WINIX_ERR_CANT_CHANGE_GROUP )
|
2013-03-26 01:04:01 +01:00
|
|
|
{
|
2010-08-12 21:10:12 +02:00
|
|
|
header = h_403;
|
2013-03-26 01:04:01 +01:00
|
|
|
log << log2 << "App: http response: 403 Forbidden" << logend;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cur.request->use_200_status_for_not_found_and_permission_denied && (header == h_404 || header == h_403) )
|
|
|
|
{
|
|
|
|
log << log3 << "App: changing the http response to: 200 OK" << logend;
|
|
|
|
header = h_200;
|
|
|
|
}
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void App::SendTextAnswer()
|
|
|
|
{
|
|
|
|
const std::wstring * source;
|
|
|
|
bool compressing = false;
|
|
|
|
int compress_encoding = 0;
|
|
|
|
size_t output_size = 0;
|
|
|
|
|
|
|
|
Header header = GetHTTPStatusCode();
|
|
|
|
|
|
|
|
if( CanSendContent() )
|
|
|
|
{
|
|
|
|
FilterContent();
|
|
|
|
|
|
|
|
if( cur.request->return_json )
|
|
|
|
{
|
|
|
|
CreateJSONAnswer();
|
|
|
|
source = &json_out_stream.Str(); // json_out_stream was prepared by CreateJSONAnswer()
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-15 23:23:36 +01:00
|
|
|
source = &cur.request->out_main_stream.Str();
|
2013-12-04 02:21:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
SelectCompression(source->length(), compressing, compress_encoding);
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
PT::WideToUTF8(*source, output_8bit);
|
2013-12-04 02:21:57 +01:00
|
|
|
|
|
|
|
// !! IMPROVE ME add to log the binary stream as well
|
|
|
|
if( config.log_server_answer )
|
|
|
|
log << log1 << "App: the server's answer is:\n" << output_8bit << "\nApp: end of the server's answer" << logend;
|
|
|
|
|
|
|
|
if( compressing )
|
|
|
|
{
|
|
|
|
compress.Compressing(output_8bit.c_str(), output_8bit.length(), compressed_output, compress_encoding);
|
|
|
|
output_size = compressed_output.size();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
output_size = output_8bit.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PrepareHeaders(compressing, compress_encoding, header, output_size);
|
2013-11-29 22:39:23 +01:00
|
|
|
SendHeaders();
|
|
|
|
SendCookies();
|
|
|
|
FCGX_PutS("\r\n", fcgi_request.out);
|
2010-08-10 18:12:50 +02:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
if( CanSendContent() )
|
2010-08-12 21:10:12 +02:00
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
if( compressing )
|
|
|
|
SendData(compressed_output, fcgi_request.out);
|
|
|
|
else
|
|
|
|
FCGX_PutStr(output_8bit.c_str(), output_8bit.size(), fcgi_request.out);
|
2010-08-12 21:10:12 +02:00
|
|
|
}
|
|
|
|
}
|
2010-10-24 19:49:38 +02:00
|
|
|
|
|
|
|
|
2012-09-11 07:19:45 +02:00
|
|
|
void App::SendData(const BinaryPage & page, FCGX_Stream * out)
|
|
|
|
{
|
|
|
|
const size_t buf_size = 4096;
|
|
|
|
|
|
|
|
if( send_data_buf.size() != buf_size )
|
|
|
|
send_data_buf.resize(buf_size);
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
BinaryPage::const_iterator i = page.begin();
|
2012-09-11 07:19:45 +02:00
|
|
|
BinaryPage::const_iterator end = page.end();
|
|
|
|
|
|
|
|
while( i != end )
|
|
|
|
{
|
|
|
|
size_t s = 0;
|
|
|
|
|
|
|
|
for( ; i != end && s < buf_size ; ++i, ++s)
|
|
|
|
send_data_buf[s] = *i;
|
|
|
|
|
|
|
|
if( s > 0 )
|
2013-11-29 22:39:23 +01:00
|
|
|
FCGX_PutStr(send_data_buf.c_str(), s, out);
|
2012-09-11 07:19:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::SendBinaryAnswer()
|
|
|
|
{
|
2013-11-14 21:59:23 +01:00
|
|
|
BinaryPage & source = cur.request->out_bin_stream;
|
2012-09-11 07:19:45 +02:00
|
|
|
Header header = h_200;
|
|
|
|
Error status = cur.request->status;
|
|
|
|
bool compressing;
|
|
|
|
int compress_encoding;
|
|
|
|
|
|
|
|
SelectCompression(source.size(), compressing, compress_encoding);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
// !! IMPROVE ME add header: content-length (size from Item struct)
|
|
|
|
// warning: if someone changed a file on the disk (in the real os)
|
|
|
|
// then winix would send an incorrect content-lenght header,
|
|
|
|
// we are waiting for the fsck winix function to be implemented
|
|
|
|
PrepareHeaders(compressing, compress_encoding, header, static_cast<size_t>(-1));
|
2013-12-19 18:19:47 +01:00
|
|
|
SendHeaders();
|
|
|
|
SendCookies();
|
|
|
|
FCGX_PutS("\r\n", fcgi_request.out);
|
2012-09-11 07:19:45 +02:00
|
|
|
|
2013-12-04 02:21:57 +01:00
|
|
|
if( CanSendContent() )
|
2012-09-11 07:19:45 +02:00
|
|
|
{
|
|
|
|
if( compressing )
|
|
|
|
{
|
2013-12-04 02:21:57 +01:00
|
|
|
compress.Compressing(source, compressed_output, compress_encoding);
|
|
|
|
SendData(compressed_output, fcgi_request.out);
|
2012-09-11 07:19:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SendData(source, fcgi_request.out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::SendAnswer()
|
|
|
|
{
|
2019-02-19 11:36:20 +01:00
|
|
|
if( !cur.request->info_serializer )
|
|
|
|
{
|
|
|
|
json_generic_serializer.Clear(); // !! IMPROVE ME add to the end of a request
|
|
|
|
cur.request->info_serializer = &json_generic_serializer;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cur.request->return_json )
|
|
|
|
PrepareStandardJSONFields();
|
|
|
|
|
2013-11-14 21:59:23 +01:00
|
|
|
if( cur.request->send_bin_stream )
|
2012-09-11 07:19:45 +02:00
|
|
|
SendBinaryAnswer();
|
2013-11-14 21:59:23 +01:00
|
|
|
else
|
|
|
|
SendTextAnswer();
|
2012-09-11 07:19:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 19:49:38 +02:00
|
|
|
void App::LogUser(const char * msg, uid_t id)
|
|
|
|
{
|
2010-10-24 21:26:54 +02:00
|
|
|
log << log3 << msg << " ";
|
|
|
|
|
|
|
|
passwd * p = getpwuid(id);
|
|
|
|
|
|
|
|
if( p )
|
|
|
|
log << p->pw_name;
|
|
|
|
else
|
2010-10-24 21:31:43 +02:00
|
|
|
log << (int)id;
|
2010-10-24 21:26:54 +02:00
|
|
|
|
|
|
|
log << logend;
|
2010-10-24 19:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::LogGroup(const char * msg, gid_t id, bool put_logend)
|
|
|
|
{
|
|
|
|
log << log3 << msg << " ";
|
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
group * g = getgrgid(id);
|
|
|
|
|
|
|
|
if( g )
|
|
|
|
log << g->gr_name;
|
|
|
|
else
|
|
|
|
log << (int)id;
|
|
|
|
|
|
|
|
if( put_logend )
|
|
|
|
log << logend;
|
2010-10-24 19:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::LogUsers()
|
|
|
|
{
|
2010-10-24 21:26:54 +02:00
|
|
|
uid_t eid, rid;
|
2010-11-21 01:19:17 +01:00
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
eid = geteuid();
|
|
|
|
rid = getuid();
|
|
|
|
|
|
|
|
if( eid == rid )
|
|
|
|
{
|
|
|
|
LogUser("App: effective/real user:", eid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LogUser("App: effective user:", eid);
|
|
|
|
LogUser("App: real user:", rid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void App::LogEffectiveGroups(std::vector<gid_t> & tab)
|
|
|
|
{
|
|
|
|
log << log3 << "App: effective groups:";
|
|
|
|
|
|
|
|
for(size_t i=0 ; i<tab.size() ; ++i)
|
|
|
|
{
|
|
|
|
bool was_printed = false;
|
|
|
|
|
|
|
|
for(size_t x=0 ; x<i ; ++x)
|
|
|
|
{
|
|
|
|
if( tab[i] == tab[x] )
|
|
|
|
{
|
|
|
|
was_printed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !was_printed )
|
|
|
|
LogGroup("", tab[i], false);
|
|
|
|
}
|
|
|
|
|
|
|
|
log << logend;
|
|
|
|
}
|
2010-10-24 19:49:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
void App::LogGroups()
|
|
|
|
{
|
2010-10-24 21:26:54 +02:00
|
|
|
std::vector<gid_t> tab;
|
|
|
|
gid_t rgid;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
rgid = getgid();
|
|
|
|
len = getgroups(0, 0);
|
|
|
|
|
|
|
|
if( len <= 0 )
|
|
|
|
{
|
|
|
|
log << log3 << "App: I can't read how many groups there are" << logend;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tab.resize(len);
|
|
|
|
len = getgroups(len, &(tab[0]));
|
|
|
|
|
|
|
|
if( len == -1 )
|
|
|
|
{
|
|
|
|
log << log3 << "App: I can't read groups" << logend;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( len == 1 && rgid == tab[0] )
|
|
|
|
{
|
|
|
|
LogGroup("App: effective/real group:", rgid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tab.resize(len);
|
|
|
|
LogEffectiveGroups(tab);
|
|
|
|
LogGroup("App: real group:", rgid);
|
|
|
|
}
|
2010-10-24 19:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::LogUserGroups()
|
|
|
|
{
|
2010-10-24 21:26:54 +02:00
|
|
|
LogUsers();
|
|
|
|
LogGroups();
|
2018-11-21 18:51:15 +01:00
|
|
|
|
|
|
|
log << log3 << "base_url: " << config.base_url << logend;
|
2010-10-24 19:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
|
|
|
bool App::DropPrivileges(char * user, char * group)
|
|
|
|
{
|
|
|
|
if( !WideToUTF8(config.user, user, WINIX_OS_USERNAME_SIZE) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( !WideToUTF8(config.group, group, WINIX_OS_USERNAME_SIZE) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool App::DropPrivileges(const char * user, uid_t uid, gid_t gid, bool additional_groups)
|
2010-10-24 19:49:38 +02:00
|
|
|
{
|
|
|
|
if( additional_groups )
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
if( initgroups(user, gid) < 0 )
|
2010-10-24 21:26:54 +02:00
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
log << log1 << "App: I can't init groups for a user: " << user << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( setgroups(1, &gid) < 0 )
|
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: I can't init groups for user: " << user << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// for setting real and saved gid too
|
2014-10-09 22:44:56 +02:00
|
|
|
if( setgid(gid) < 0 )
|
2010-10-24 21:26:54 +02:00
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: I can't change real and saved gid" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( setuid(uid) < 0 )
|
|
|
|
{
|
|
|
|
log << log1 << "App: I can't drop privileges to user: " << user
|
2011-01-05 22:24:11 +01:00
|
|
|
<< " (uid:" << (int)uid << ")" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( getuid()==0 || geteuid()==0 )
|
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: sorry, for security reasons you should not run me as the root" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
bool App::DropPrivileges()
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
char user_name[WINIX_OS_USERNAME_SIZE];
|
|
|
|
char group_name[WINIX_OS_USERNAME_SIZE];
|
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
if( getuid()!=0 && geteuid()!=0 )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
log << log2 << "App: dropping privileges" << logend;
|
|
|
|
|
|
|
|
if( config.user.empty() )
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
log << log1 << "App: in the config file you should specify a user name and a group "
|
2011-01-05 22:24:11 +01:00
|
|
|
<< "to which I have to drop privileges" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( config.group.empty() )
|
|
|
|
{
|
2014-10-09 22:44:56 +02:00
|
|
|
log << log1 << "App: you should specify a group name in the config file "
|
2011-01-05 22:24:11 +01:00
|
|
|
<< "to which I have to drop privileges" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( !DropPrivileges(user_name, group_name) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
passwd * p = getpwnam(user_name);
|
|
|
|
group * g = getgrnam(group_name);
|
2010-10-24 21:26:54 +02:00
|
|
|
|
|
|
|
if( !p )
|
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: there is no such a user as: \"" << config.user << "\"" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !g )
|
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: there is no such a group as: \"" << config.group << "\"" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
if( !DropPrivileges(user_name, p->pw_uid, g->gr_gid, config.additional_groups) )
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
2010-10-24 19:49:38 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
|
|
|
|
bool App::Demonize()
|
|
|
|
{
|
|
|
|
// in linux fork() should be used twice
|
|
|
|
|
|
|
|
int pid = fork();
|
|
|
|
|
|
|
|
if( pid == -1 )
|
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: I can't demonize myself (fork problem)" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pid != 0 )
|
|
|
|
{
|
|
|
|
// parent
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// child
|
|
|
|
if( setsid() == -1 )
|
|
|
|
{
|
2011-01-05 22:24:11 +01:00
|
|
|
log << log1 << "App: I can't demonize myself (setsid problem)" << logend;
|
2010-10-24 21:26:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-11-23 22:52:25 +01:00
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
// this method is called from a signal routine
|
|
|
|
void App::SetStopSignal()
|
|
|
|
{
|
|
|
|
synchro.was_stop_signal = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool App::WasStopSignal()
|
|
|
|
{
|
|
|
|
return synchro.was_stop_signal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool App::Lock()
|
|
|
|
{
|
|
|
|
return synchro.Lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::Unlock()
|
|
|
|
{
|
|
|
|
synchro.Unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void App::WaitForThreads()
|
|
|
|
{
|
2014-02-11 22:00:32 +01:00
|
|
|
pthread_join(signal_thread, 0);
|
2011-07-29 00:18:10 +02:00
|
|
|
system.thread_manager.StopAll();
|
2010-12-02 02:02:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-09 22:44:56 +02:00
|
|
|
|
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
/*
|
|
|
|
we send a one FastCGI record at the end when winix closes (to wake up the main thread)
|
|
|
|
this method is called from the special thread
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
unsigned char version;
|
|
|
|
unsigned char type;
|
|
|
|
unsigned char requestIdB1;
|
|
|
|
unsigned char requestIdB0;
|
|
|
|
unsigned char contentLengthB1;
|
|
|
|
unsigned char contentLengthB0;
|
|
|
|
unsigned char paddingLength;
|
|
|
|
unsigned char reserved;
|
|
|
|
unsigned char contentData[contentLength];
|
|
|
|
unsigned char paddingData[paddingLength];
|
|
|
|
} FCGI_Record;
|
|
|
|
*/
|
|
|
|
void App::SendEmptyFastCGIPacket()
|
|
|
|
{
|
|
|
|
std::string msg;
|
|
|
|
sockaddr_un to;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
int s = socket(PF_LOCAL, SOCK_STREAM, 0);
|
|
|
|
|
|
|
|
if( s < 0 )
|
|
|
|
return;
|
2010-12-02 02:02:02 +01:00
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
memset(&to, 0, sizeof(to));
|
2015-01-02 08:14:15 +01:00
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
to.sun_len = offsetof(sockaddr_un, sun_path)
|
2015-01-02 08:01:08 +01:00
|
|
|
+ socket_to_send_on_exit.size()
|
|
|
|
+ 1; // terminating zero
|
2015-01-02 08:14:15 +01:00
|
|
|
#endif
|
2014-02-11 22:00:32 +01:00
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
to.sun_family = AF_UNIX;
|
|
|
|
snprintf(to.sun_path, sizeof(to.sun_path)/sizeof(char), "%s", socket_to_send_on_exit.c_str());
|
2014-10-09 22:44:56 +02:00
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
// actually we can send one byte only
|
|
|
|
msg += FCGI_VERSION_1;
|
|
|
|
msg += FCGI_GET_VALUES;
|
|
|
|
msg += (char)0; // requestid
|
|
|
|
msg += (char)0;
|
|
|
|
msg += (char)0; // contentlength
|
|
|
|
msg += (char)0;
|
|
|
|
msg += (char)0; // padding length
|
|
|
|
msg += (char)0;
|
|
|
|
msg += (char)0; // reserved
|
2014-10-09 22:44:56 +02:00
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
res = connect(s, (sockaddr*)&to, sizeof(to));
|
|
|
|
|
|
|
|
if( res == 0 )
|
|
|
|
{
|
2015-01-02 08:15:22 +01:00
|
|
|
send(s, msg.c_str(), msg.size(), 0);
|
2014-02-11 22:00:32 +01:00
|
|
|
}
|
2015-01-02 08:01:08 +01:00
|
|
|
|
|
|
|
close(s);
|
2010-12-02 02:02:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void * App::SpecialThreadForSignals(void * app_object)
|
2010-11-23 22:52:25 +01:00
|
|
|
{
|
2010-12-02 02:02:02 +01:00
|
|
|
sigset_t set;
|
2014-02-12 18:21:42 +01:00
|
|
|
int sig;
|
2010-12-02 02:02:02 +01:00
|
|
|
|
|
|
|
App * app = reinterpret_cast<App*>(app_object);
|
|
|
|
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIGTERM);
|
|
|
|
sigaddset(&set, SIGINT);
|
|
|
|
|
|
|
|
// waiting for SIGTERM or SIGINT
|
2014-02-12 18:21:42 +01:00
|
|
|
sigwait(&set, &sig);
|
2010-12-02 02:02:02 +01:00
|
|
|
|
|
|
|
app->Lock();
|
|
|
|
app->synchro.was_stop_signal = true;
|
|
|
|
FCGX_ShutdownPending();
|
2011-08-18 01:09:47 +02:00
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
PT::WideToUTF8(app->config.fcgi_socket, app->socket_to_send_on_exit);
|
2010-12-02 02:02:02 +01:00
|
|
|
app->Unlock();
|
|
|
|
|
2015-01-02 08:01:08 +01:00
|
|
|
app->SendEmptyFastCGIPacket();
|
2010-12-02 02:02:02 +01:00
|
|
|
|
|
|
|
pthread_exit(0);
|
|
|
|
return 0;
|
2010-11-23 22:52:25 +01:00
|
|
|
}
|
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
|
|
|
|
|
|
|
|
void App::StartThreads()
|
|
|
|
{
|
2011-07-29 00:18:10 +02:00
|
|
|
// make sure system.thread_manager.Init() was called beforehand
|
|
|
|
// it is called in Init() -> system.Init()
|
2010-12-02 02:02:02 +01:00
|
|
|
|
|
|
|
// special thread only for signals
|
|
|
|
pthread_create(&signal_thread, 0, SpecialThreadForSignals, this);
|
|
|
|
|
2012-05-19 19:04:33 +02:00
|
|
|
system.thread_manager.Add(&session_manager, L"session_manager");
|
2011-07-29 00:18:10 +02:00
|
|
|
system.thread_manager.StartAll();
|
2010-12-02 02:02:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-10 22:07:01 +01:00
|
|
|
void App::CreateStaticTree()
|
|
|
|
{
|
|
|
|
if( config.upload_dir.empty() )
|
|
|
|
{
|
|
|
|
log << log1 << "App: config: upload_dir not set, you are not allowed to upload static content" << logend;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CreateDirs(L"/", config.upload_dir.c_str(), config.upload_dirs_chmod);
|
|
|
|
|
|
|
|
CreateDirs(config.upload_dir.c_str(), L"simplefs/normal", config.upload_dirs_chmod);
|
|
|
|
CreateDirs(config.upload_dir.c_str(), L"simplefs/thumb", config.upload_dirs_chmod);
|
|
|
|
|
|
|
|
CreateDirs(config.upload_dir.c_str(), L"hashfs/normal", config.upload_dirs_chmod);
|
|
|
|
CreateDirs(config.upload_dir.c_str(), L"hashfs/thumb", config.upload_dirs_chmod);
|
|
|
|
|
|
|
|
CreateDirs(config.upload_dir.c_str(), L"tmp", config.upload_dirs_chmod);
|
|
|
|
}
|
2014-02-12 17:30:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Winix
|
|
|
|
|