removed: Request::debug all stream used for debugging info

some environment variables were put there
removed: config variable: debug_info
removed: Request::role (responder, authorizer)
         now we have only one role: responder
added:   new config variables:
         log_env_variables (default false) - when true then fastcgi environment
         variables are logged to the log file
         log_http_answer_headers (default false) - when true all http headers
         created by winix ale logged (note that the www server can add/adjust other headers)
changed: some refactoring in Request struct
changed: CookieTab to std::map<std::wstring, std::wstring>
         beforehand std::string was used
         (changed CookieParser as well)
changed: Request::SetCookie() to AddCookie()
added:   Request::out_headers (a PT::Space struct)
         http headers (without cookies) send back to the client
added:   Request::out_cookies (a PT::Space struct)
         cookies send to the client
changed: App class to use Request::out_headers and Request::out_cookies
         some SendHeaders...() methods were renamed to PrepareHeaders...()
         and they create output in Request::out_headers first (and out_cookies)
         and later it is sent
added:   two plugin messages:
         // http headers (without cookies) were created and are ready to send
         // here you can make some changes to them
         // in p1 you have a pointer to the PT::Space (Request::out_headers)
         #define WINIX_PREPARE_TO_SEND_HTTP_HEADERS		31070

         // http cookies were created and are ready to send
         // here you can make some changes to them
         // in p1 you have a pointer to the PT::Space (Request::out_cookies)
         #define WINIX_PREPARE_TO_SEND_HTTP_COOKIES		31080
added:   config variable:
         // how many output streams do we have in Request class
         // default: 16 (64 maximum)
         size_t ezc_out_streams_size;




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@940 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2013-11-29 21:39:23 +00:00
parent 3e32f3784f
commit 375604edd6
11 changed files with 419 additions and 302 deletions

View File

@ -162,6 +162,8 @@ bool App::Init()
post_parser.LogValueSize(config.log_post_value_size);
// post_multi_parser has a pointer to the config
cookie_parser.UTF8(config.utf8);
plugin.Call((Session*)0, WINIX_PLUGIN_INIT);
return true;
@ -572,26 +574,13 @@ void App::Make()
plugin.Call(WINIX_CONTENT_MAKE);
MakePage();
if( config.debug_info )
{
// !! dodac inne informacje (get, post, itp)
// jesli jest debug_info wlaczone to nie robic przekierowan
PrintEnv();
}
}
void App::PrintEnv()
void App::LogEnvironmentVariables()
{
char ** e;
cur.request->debug << "environment variables:\n";
for( e = fcgi_request.envp ; *e ; ++e )
cur.request->debug << ' ' << *e << "\n";
cur.request->debug << '\n';
for(char ** e = fcgi_request.envp ; *e ; ++e )
log << log1 << "Env: " << *e << logend;
}
@ -601,7 +590,6 @@ void App::ReadRequest()
{
ReadEnvVariables();
CheckRequestMethod();
CheckFCGIRole();
CheckSSL();
SetSubdomain();
@ -611,14 +599,14 @@ void App::ReadRequest()
cookie_parser.Parse(cur.request->env_http_cookie, cur.request->cookie_tab);
accept_encoding_parser.ParseAndLog(cur.request->env_http_accept_encoding);
if( config.log_env_variables )
LogEnvironmentVariables();
CheckIE();
CheckKonqueror();
if( cur.request->using_ssl )
log << log3 << "App: connection secure through SSL" << logend;
if( cur.request->role == Request::authorizer )
log << log3 << "App: fast cgi role: authorizer" << logend;
}
@ -658,7 +646,7 @@ void App::ReadEnvVariables()
void App::CheckRequestMethod()
{
cur.request->method = Request::none;
cur.request->method = Request::unknown_method;
if( ToSmall(cur.request->env_request_method[0]) == 'g' )
cur.request->method = Request::get;
@ -671,15 +659,6 @@ void App::CheckRequestMethod()
}
void App::CheckFCGIRole()
{
// default we assume 'responder'
cur.request->role = Request::responder;
if( ToSmall(cur.request->env_fcgi_role[0]) == 'a' )
cur.request->role = Request::authorizer;
}
void App::CheckSSL()
{
@ -774,22 +753,21 @@ void App::PrepareSessionCookie()
if( !cur.session->puser || !cur.session->remember_me )
{
cur.request->SetCookie(config.http_session_id_name.c_str(), cur.session->id);
cur.request->AddCookie(config.http_session_id_name, cur.session->id);
}
else
{
PT::Date expires = cur.request->start_time + config.session_remember_max_idle;
cur.request->SetCookie(config.http_session_id_name.c_str(), cur.session->id, &expires);
cur.request->AddCookie(config.http_session_id_name, cur.session->id, expires);
}
}
bool App::SendHeadersStaticCreateResource()
bool App::PrepareHeadersStaticCreateResource(PT::WTextStream & out_path)
{
size_t i = 0;
Item * dir = system.dirs.GetDir(system.mounts.pmount->dir_id);
sendh_t3.clear();
if( !dir )
{
@ -808,18 +786,18 @@ bool App::SendHeadersStaticCreateResource()
++i;
if( i > 0 )
sendh_t3.assign(path, i);
out_path.write(path, i);
return true;
}
void App::SendHeadersStatic()
void App::PrepareHeadersStatic()
{
if( PathHasUpDir(cur.request->env_request_uri) )
{
log << log1 << "App: incorrect path for a static file" << logend;
SendHeadersForbidden();
PrepareHeadersForbidden();
return;
}
@ -829,171 +807,213 @@ void App::SendHeadersStatic()
if( index >= config.static_dirs.size() )
{
log << log1 << "App: static dir with index " << index << " is not defined in the config" << logend;
SendHeadersForbidden();
PrepareHeadersForbidden();
return;
}
PT::WideToUTF8(config.http_header_send_file, sendh_t);
PT::WideToUTF8(config.static_dirs[index], sendh_t2);
PT::WTextStream path;
path << config.static_dirs[index] << L"/";
if( !SendHeadersStaticCreateResource() )
if( !PrepareHeadersStaticCreateResource(path) )
{
SendHeadersForbidden();
PrepareHeadersForbidden();
return;
}
FCGX_FPrintF(fcgi_request.out, "%s: %s/%s\r\n", sendh_t.c_str(), sendh_t2.c_str(), sendh_t3.c_str());
FCGX_PutS("Status: 200 OK\r\n", fcgi_request.out);
log << log2 << "App: sending a file from a static mountpoint: " << sendh_t2 << "/" << sendh_t3 << logend;
cur.request->out_headers.Add(config.http_header_send_file, path);
cur.request->out_headers.Add(L"Status", L"200 OK");
log << log2 << "App: sending a file from a static mountpoint: " << path << logend;
}
void App::SendHeaderContentType()
void App::PrepareHeaderContentType()
{
std::wstring * value = 0;
if( cur.request->return_json )
{
FCGX_PutS("Content-Type: application/json", fcgi_request.out);
value = &cur.request->out_headers.Add(L"Content-Type", L"application/json");
}
else
{
switch( config.content_type_header )
{
case 1:
FCGX_PutS("Content-Type: application/xhtml+xml", fcgi_request.out);
value = &cur.request->out_headers.Add(L"Content-Type", L"application/xhtml+xml");
break;
case 2:
FCGX_PutS("Content-Type: application/xml", fcgi_request.out);
value = &cur.request->out_headers.Add(L"Content-Type", L"application/xml");
break;
case 0:
default:
FCGX_PutS("Content-Type: text/html", fcgi_request.out);
value = &cur.request->out_headers.Add(L"Content-Type", L"text/html");
}
}
if( config.utf8 )
FCGX_PutS("; charset=UTF-8", fcgi_request.out);
FCGX_PutS("\r\n", fcgi_request.out);
if( value && config.utf8 )
*value += L"; charset=UTF-8";
}
void App::SendHeadersForbidden()
void App::PrepareHeadersForbidden()
{
FCGX_PutS("Status: 403 Forbidden\r\n", fcgi_request.out);
SendHeaderContentType();
cur.request->out_headers.Add(L"Status", L"403 Forbidden");
PrepareHeaderContentType();
}
void App::SendHeadersRedirect()
void App::PrepareHeadersRedirect()
{
switch(cur.request->redirect_type)
{
case 300:
FCGX_PutS("Status: 300 Multiple Choices\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Status", L"300 Multiple Choices");
break;
case 301:
FCGX_PutS("Status: 301 Moved Permanently\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Status", L"301 Moved Permanently");
break;
case 302:
FCGX_PutS("Status: 302 Found\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Status", L"302 Found");
break;
case 307:
FCGX_PutS("Status: 307 Temporary Redirect\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Status", L"307 Temporary Redirect");
break;
case 303:
default:
FCGX_PutS("Status: 303 See Other\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Status", L"303 See Other");
break;
}
PT::WideToUTF8(cur.request->redirect_to, cur.request->aredirect_to);
FCGX_FPrintF(fcgi_request.out, "Location: %s\r\n", cur.request->aredirect_to.c_str());
log << log2 << "App: redirect to: " << cur.request->aredirect_to << logend;
cur.request->out_headers.Add(L"Location", cur.request->redirect_to);
log << log2 << "App: redirect to: " << cur.request->redirect_to << logend;
}
void App::SendHeadersSendFile()
void App::PrepareHeadersSendFile()
{
PT::WideToUTF8(config.http_header_send_file, sendfilea);
PT::WideToUTF8(cur.request->x_sendfile, sendfile2a);
FCGX_FPrintF(fcgi_request.out, "%s: %s\r\n", sendfilea.c_str(), sendfile2a.c_str());
cur.request->out_headers.Add(L"Status", L"200 OK");
cur.request->out_headers.Add(config.http_header_send_file, cur.request->x_sendfile);
FCGX_PutS("Status: 200 OK\r\n", fcgi_request.out);
log << log2 << "App: sending file: " << cur.request->x_sendfile << logend;
}
void App::SendHeadersCompression(int compress_encoding)
void App::PrepareHeadersCompression(int compress_encoding)
{
if( compress_encoding == 0 || compress_encoding == 1 )
FCGX_PutS("Content-Encoding: deflate\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Content-Encoding", L"deflate");
else
FCGX_PutS("Content-Encoding: gzip\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Content-Encoding", L"gzip");
}
void App::SendHeadersNormal(Header header)
void App::PrepareHeadersNormal(Header header)
{
switch( header )
{
case h_404:
FCGX_PutS("Status: 404 Not Found\r\n", fcgi_request.out);
SendHeaderContentType();
cur.request->out_headers.Add(L"Status", L"404 Not Found");
PrepareHeaderContentType();
break;
case h_403:
SendHeadersForbidden();
PrepareHeadersForbidden();
break;
default:
FCGX_PutS("Status: 200 OK\r\n", fcgi_request.out);
if( cur.request->role != Request::authorizer )
SendHeaderContentType();
cur.request->out_headers.Add(L"Status", L"200 OK");
PrepareHeaderContentType();
}
}
// 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()
{
PT::Space::TableSingle::iterator i;
PT::Space & headers = cur.request->out_headers;
void App::SendHeaders(bool compressing, int compress_encoding, Header header)
plugin.Call(WINIX_PREPARE_TO_SEND_HTTP_HEADERS, &headers);
for(i=headers.table_single.begin() ; i != headers.table_single.end() ; ++i)
{
PT::WideToUTF8(i->first, aheader_name);
PT::WideToUTF8(i->second, aheader_value);
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);
if( config.log_http_answer_headers )
log << "HTTP Header: " << aheader_name << ": " << aheader_value << logend;
}
}
void App::SendCookies()
{
PT::Space::TableSingle::iterator i;
PT::Space & cookies = cur.request->out_cookies;
plugin.Call(WINIX_PREPARE_TO_SEND_HTTP_COOKIES, &cookies);
for(i=cookies.table_single.begin() ; i != cookies.table_single.end() ; ++i)
{
PT::WideToUTF8(i->first, aheader_name);
PT::WideToUTF8(i->second, aheader_value);
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);
if( config.log_http_answer_headers )
log << "HTTP Header: " << "Set-Cookie: " << aheader_name << "=" << aheader_value << logend;
}
}
void App::PrepareHeaders(bool compressing, int compress_encoding, Header header)
{
PrepareSessionCookie();
if( cur.request->send_as_attachment )
FCGX_PutS("Content-Disposition: attachment\r\n", fcgi_request.out);
cur.request->out_headers.Add(L"Content-Disposition", L"attachment");
if( !cur.request->redirect_to.empty() )
{
SendHeadersRedirect();
PrepareHeadersRedirect();
}
else
if( system.mounts.pmount->type == system.mounts.MountTypeStatic() )
{
SendHeadersStatic();
PrepareHeadersStatic();
}
else
if( !cur.request->x_sendfile.empty() )
{
SendHeadersSendFile();
PrepareHeadersSendFile();
}
else
{
SendHeadersNormal(header);
PrepareHeadersNormal(header);
}
if( compressing )
SendHeadersCompression(compress_encoding);
FCGX_PutS(cur.request->headers.CStr(), fcgi_request.out);
FCGX_PutS("\r\n", fcgi_request.out);
PrepareHeadersCompression(compress_encoding);
}
@ -1009,13 +1029,11 @@ void App::FilterCompressSend(bool compressing, int compress_encoding, const std:
if( config.html_filter && cur.request->use_html_filter && !raw && !cur.request->return_json )
{
TemplatesFunctions::html_filter.Filter(*source, clean_html);
AddDebugInfo(clean_html);
source = &clean_html;
}
else
{
html_with_debug = *source;
AddDebugInfo(html_with_debug);
source = &html_with_debug;
}
@ -1024,6 +1042,7 @@ void App::FilterCompressSend(bool compressing, int compress_encoding, const std:
else
AssignString(*source, source_a);
// !! IMPROVE ME add to log the binary stream as well
if( config.log_server_answer )
log << log1 << "App: the server's answer is:\n" << source_a << "\nApp: end of the server's answer" << logend;
@ -1054,7 +1073,6 @@ void App::SelectCompression(size_t source_len, bool & compression_allowed, int &
compression_encoding = 0;
if( config.compression &&
cur.request->role == Request::responder &&
cur.request->redirect_to.empty() &&
cur.request->x_sendfile.empty() &&
!cur.request->browser_konqueror && /* !! sprawdzic czy Konqueror bedzie obslugiwal raw deflate */
@ -1102,10 +1120,6 @@ bool App::CanSendContent(Header header)
// if there is a redirect or a file to send then we do not send a content
return false;
if( header == h_200 && cur.request->role == Request::authorizer && cur.request->is_item && cur.request->item.file_type != WINIX_ITEM_FILETYPE_NONE )
// if there is an item and the item has 'file' storage we do not send a content
return false;
/*
we don't have to check the HEAD method
the server (lighttpd) doesn't send the body of its own
@ -1117,18 +1131,6 @@ return true;
}
void App::AddDebugInfo(std::wstring & out)
{
if( config.debug_info )
{
if( !cur.request->debug.Empty() )
{
out += L"\n<!--\n";
out += cur.request->debug.Str();
out += L"\n-->\n";
}
}
}
@ -1165,7 +1167,10 @@ int compress_encoding;
header = h_200;
}
SendHeaders(compressing, compress_encoding, header);
PrepareHeaders(compressing, compress_encoding, header);
SendHeaders();
SendCookies();
FCGX_PutS("\r\n", fcgi_request.out);
if( CanSendContent(header) )
{
@ -1193,7 +1198,7 @@ void App::SendData(const BinaryPage & page, FCGX_Stream * out)
send_data_buf[s] = *i;
if( s > 0 )
FCGX_PutStr(send_data_buf.c_str(), s, fcgi_request.out);
FCGX_PutStr(send_data_buf.c_str(), s, out);
}
}
@ -1216,7 +1221,7 @@ int compress_encoding;
// !! IMPROVE ME add header: content-size
SendHeaders(compressing, compress_encoding, header);
PrepareHeaders(compressing, compress_encoding, header);
if( CanSendContent(header) )
{
@ -1519,6 +1524,9 @@ void App::WaitForThreads()
void App::FetchPageOnExit()
{
// !! CHANGE ME use curl instead of BSD's fetch...
// this allows to port to Linux systems
// stupid trick to break FCGX_Accept_r() function
// even with FCGX_InitRequest(..., ..., FCGI_FAIL_ACCEPT_ON_INTR) the FCGX_Accept_r
// doesn't want to break on a signal

View File

@ -119,12 +119,11 @@ private:
pthread_t signal_thread;
std::string url_to_fetch_on_exit;
std::string source_a;
std::string sendh_t, sendh_t2, sendh_t3;
std::string sendfilea, sendfile2a;
std::string send_data_buf;
PT::SpaceToJSON json_generic_serializer;
TextStream<std::wstring> json_out_stream;
BinaryPage out_bin_stream_compressed;
std::string aheader_name, aheader_value;
bool CheckAccessFromPlugins();
void ProcessRequestThrow();
@ -146,7 +145,7 @@ private:
void SendBinaryAnswer();
void SendAnswer();
void PrintEnv();
void LogEnvironmentVariables();
void SetEnv(const char * & env, const char * name);
void ReadEnvVariables();
@ -155,23 +154,23 @@ private:
void CheckIE();
void CheckKonqueror();
void CheckRequestMethod();
void CheckFCGIRole();
void CheckSSL();
void SetSubdomain();
void PrepareSessionCookie();
void AddDebugInfo(std::wstring & out);
void FilterCompressSend(bool compressing, int compress_encoding, const std::wstring & source_ref);
bool SendHeadersStaticCreateResource();
void SendHeadersStatic();
void SendHeaderContentType();
void SendHeadersForbidden();
void SendHeadersRedirect();
void SendHeadersSendFile();
void SendHeadersCompression(int compress_encoding);
void SendHeadersNormal(Header header);
void SendHeaders(bool compressing, int compress_encoding, Header header);
void SendHeaders();
void SendCookies();
bool PrepareHeadersStaticCreateResource(PT::WTextStream & out_path);
void PrepareHeadersStatic();
void PrepareHeaderContentType();
void PrepareHeadersForbidden();
void PrepareHeadersRedirect();
void PrepareHeadersSendFile();
void PrepareHeadersCompression(int compress_encoding);
void PrepareHeadersNormal(Header header);
void PrepareHeaders(bool compressing, int compress_encoding, Header header);
int SelectDeflateVersion();
void SelectCompression(size_t source_len, bool & compression_allowed, int & compression_encoding);
bool CanSendContent(Header header);

View File

@ -118,6 +118,8 @@ void Config::AssignValues(bool stdout_is_closed)
log_db_query = Bool(L"log_db_query", false);
log_plugin_call = Bool(L"log_plugin_call", false);
log_post_value_size = Size(L"log_post_value_size", 80);
log_env_variables = Bool(L"log_env_variables", false);
log_http_answer_headers = Bool(L"log_http_answer_headers", false);
post_file_max = Size(L"post_file_max", 8388608); // 8 MB
@ -151,7 +153,7 @@ void Config::AssignValues(bool stdout_is_closed)
templates_index = Text(L"templates_index", L"index.html");
template_only_root_use_template_fun = Bool(L"template_only_root_use_template_fun", false);
http_session_id_name = AText(L"http_session_id_name");
http_session_id_name = Text(L"http_session_id_name", L"session_id");
db_database = AText(L"db_database");
db_user = AText(L"db_user");
db_pass = AText(L"db_pass");
@ -206,7 +208,6 @@ void Config::AssignValues(bool stdout_is_closed)
title_separator = Text(L"title_separator", L" / ");
http_header_send_file = Text(L"http_header_send_file", L"X-LIGHTTPD-send-file");
debug_info = Bool(L"debug_info", false);
editors_html_safe_mode = Bool(L"editors_html_safe_mode", true);
editors_html_safe_mode_skip_root = Bool(L"editors_html_safe_mode_skip_root", true);
@ -237,6 +238,7 @@ void Config::AssignValues(bool stdout_is_closed)
ezc_max_elements = Size(L"ezc_max_elements", 50000);
ezc_max_loop_elements = Size(L"ezc_max_loop_elements", 5000);
ezc_out_streams_size = Size(L"ezc_out_streams_size", 16);
account_need_email_verification = Bool(L"account_need_email_verification", true);
reset_password_code_expiration_time = Long(L"reset_password_code_expiration_time", 86400);
@ -259,6 +261,7 @@ void Config::AssignValues(bool stdout_is_closed)
incorrect_login_cannot_login_mode = Int(L"incorrect_login_cannot_login_mode", 0);
incorrect_login_cannot_login_treshold = Size(L"incorrect_login_cannot_login_treshold", 20);
incorrect_login_cannot_login_delay = Size(L"incorrect_login_cannot_login_delay", 1800);
}

View File

@ -91,6 +91,14 @@ public:
// request delimiter in the log file, default "---------"
std::wstring log_delimiter;
// log environment variables (fastcgi environment)
bool log_env_variables;
// log headers (+cookies) which are returned to the client
// this is what winix has generated -- the web server can change or add other headers
// default: false
bool log_http_answer_headers;
// fast cgi: socket (unix domain)
std::string fcgi_socket;
@ -128,7 +136,7 @@ public:
std::string db_user;
std::string db_pass;
std::string http_session_id_name;
std::wstring http_session_id_name;
// string used in a place where is a user (or group) selected
std::wstring priv_no_user;
@ -389,9 +397,6 @@ public:
// default: X-LIGHTTPD-send-file
std::wstring http_header_send_file;
// prints additional information (in the end of the html page as a commentary)
bool debug_info;
// in editors (emacs, ckeditor,...) the html will be filtered and unsafe tags
// will be dropped (script, frame, etc.)
// default: true;
@ -485,6 +490,10 @@ public:
// default: 5000 (from ezc generator)
size_t ezc_max_loop_elements;
// how many output streams do we have in Request class
// default: 16 (64 maximum)
size_t ezc_out_streams_size;
// when true then when a user want to create a new account
// he has to provide his email and a message will be sent back to him
// with a link to activate the account
@ -591,6 +600,7 @@ public:
Config();
bool ReadConfig(bool errors_to_stdout_, bool stdout_is_closed = true);

View File

@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* Copyright (c) 2008-2013, Tomasz Sowa
* All rights reserved.
*
*/
@ -22,6 +22,8 @@ class CookieParser : public HttpSimpleParser
const char * cookie_string;
CookieTab * cookie_tab;
std::wstring temp_name, temp_value;
bool input_as_utf8;
protected:
@ -35,19 +37,29 @@ protected:
return (int)(unsigned char)*(cookie_string++);
}
void ConvStr(const std::string & src, std::wstring & dst)
{
if( input_as_utf8 )
PT::UTF8ToWide(src, dst);
else
AssignString(src, dst);
}
virtual void Parameter(std::string & name, std::string & value)
{
// Cookie names are case insensitive according to section 3.1 of RFC 2965
// (we don't use locale here)
ToLower(name);
std::pair<CookieTab::iterator, bool> res = cookie_tab->insert( std::make_pair(name, value) );
ConvStr(name, temp_name);
ConvStr(value, temp_value);
log << log2 << "Cookie, name: \"" << name << "\", value: \"" << value << "\"";
std::pair<CookieTab::iterator, bool> res = cookie_tab->insert( std::make_pair(temp_name, temp_value) );
log << log2 << "Cookie, name: \"" << temp_name << "\", value: \"" << temp_value << "\"";
if( res.second == false )
{
res.first->second = value;
res.first->second = temp_value;
log << " (overwritten)";
}
@ -60,6 +72,7 @@ public:
CookieParser()
{
input_as_utf8 = false;
HttpSimpleParser::separator = ';';
HttpSimpleParser::value_can_be_quoted = true;
HttpSimpleParser::skip_white_chars = true;
@ -67,6 +80,11 @@ public:
}
void UTF8(bool utf)
{
input_as_utf8 = utf;
}
// cookie_string can be null
void Parse(const char * cookie_string_, CookieTab & cookie_tab_)
{

View File

@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2012, Tomasz Sowa
* Copyright (c) 2008-2013, Tomasz Sowa
* All rights reserved.
*
*/
@ -255,6 +255,15 @@
// to the resource
#define WINIX_CHECK_PLUGIN_ACCESS 31060
// http headers (without cookies) were created and are ready to send
// here you can make some changes to them
// in p1 you have a pointer to the PT::Space (Request::out_headers)
#define WINIX_PREPARE_TO_SEND_HTTP_HEADERS 31070
// http cookies were created and are ready to send
// here you can make some changes to them
// in p1 you have a pointer to the PT::Space (Request::out_cookies)
#define WINIX_PREPARE_TO_SEND_HTTP_COOKIES 31080
/*

View File

@ -34,7 +34,12 @@ void Request::SetConfig(Config * pconfig)
void Request::ClearOutputStreams()
{
out_streams.resize(16); // !! IMPROVE ME add as a constant somewhere
size_t len = config->ezc_out_streams_size;
if( len < 1 || len > 64 )
len = 16;
out_streams.resize(len);
for(size_t i=0 ; i<out_streams.size() ; ++i)
out_streams[i].Clear();
@ -54,13 +59,10 @@ void Request::Clear()
post_file_tab.clear();
cookie_tab.clear();
method = none;
role = responder;
method = unknown_method;
headers.Clear();
debug.Clear();
out_headers.Clear();
out_cookies.Clear();
page_generated = false;
use_html_filter = true;
@ -81,7 +83,7 @@ void Request::Clear()
dir_tab.clear();
last_item = &item;
is_item = false;
function = 0; // !! dodac jakas empty funkcje
function = 0;
param_tab.clear();
anchor.clear();
@ -128,43 +130,6 @@ void Request::RequestStarts()
// value can be null
void Request::SetCookie(const char * name, const char * value, PT::Date * expires)
{
headers << "Set-Cookie: " << name << "=";
if( value && value[0]!=0 )
headers << value;
else
headers << "\"\"";
if( expires )
headers << "; expires=" << DateToStrCookie(*expires) << " GMT";
headers << "; path=/; domain=" << config->base_url << "\r\n";
/*
don't use '; secure' flag if you are using both sites (with SSL
and without SSL) -- with secure flag the cookie is sent only through
SSL and if you accidentally open a new window without SSL (http://)
then winix will create a new session for you and the previous session (https://)
will be lost (cookie is overwritten on the client browser)
*/
}
void Request::SetCookie(const char * name, long value, PT::Date * expires)
{
headers << "Set-Cookie: " << name << "=" << value;
if( expires )
headers << "; expires=" << DateToStrCookie(*expires) << " GMT";
headers << "; path=/; domain=" << config->base_url << "\r\n";
}
bool Request::IsPostVar(const wchar_t * var)
{

View File

@ -22,6 +22,7 @@
#include "date/date.h"
#include "space/space.h"
#include "space/spacetojson.h"
#include "textstream/textstream.h"
@ -32,23 +33,164 @@ class FunctionBase;
struct Request
{
// request id
// is incremented for each request and is never 0
// (from -1 will be incremented twice)
// it's used for some optimalizations e.g. in templates
/*
request id
is incremented for each request and is never 0
(from -1 will be incremented to one)
it's used for some optimizations e.g. in templates
*/
size_t id;
// !! moze pozbyc sie tego none?
enum Method { get, post, head, none } method;
enum Role { responder, authorizer } role;
// headers, page and debug
//std::ostringstream headers, page, debug;
// !! IMPROVE ME change headers to some kind of a map, may PT::Space ?
TextStream<std::string> headers;
HtmlTextStream debug;
/*
request start time
Time() methods are very slow so it is better to directly use those two values
they are set when a request starts
*/
time_t start_time;
PT::Date start_date;
/*
*
*
*
* variables representing input from client's browser
*
*
*
*/
/*
the HTTP method
!! IMPROVE ME add the rest methods here
*/
enum Method { get, post, head, unknown_method } method;
/*
subdomain
subdomain = HTTP_HOST environment variable - config->base_url
*/
std::wstring subdomain;
/*
raw parameters
!! CHECK ME may post_tab and cookie_tab should be changed to PT::Space now?
or may change the name to cookie_in? or in_cookie?
*/
PostTab post_tab;
PostFileTab post_file_tab;
CookieTab cookie_tab;
/*
html anchor (those part of URI after '#' character)
*/
std::wstring anchor;
// environment variables
// they are not null -- when the server doesn't have such a variable
// it will be pointing into 'char_empty' which is default '\0'
// !! IMPROVE ME change it to std::wstring, or may PT::Space too?
const char * env_request_method;
const char * env_request_uri;
const char * env_http_cookie;
const char * env_remote_addr;
const char * env_http_host;
const char * env_http_user_agent;
const char * env_http_accept_encoding;
const char * env_fcgi_role;
const char * env_content_type;
const char * env_https;
// current IP address of the remote host (read from REMOTE_ADDR environment variable)
// (at the moment only IPv4 are supported)
int ip;
// true if the browser is Microsoft Internet Explorer
bool browser_msie;
// true if the browser is Konqueror
bool browser_konqueror;
// true if we are using an encrypted connection (SSL)
bool using_ssl;
/*
request input variables representing the winix filesystem
*/
// current directory
std::vector<Item*> dir_tab;
// true if a file exists
bool is_item;
// current file (valid if is_item is true)
Item item;
// current winix function
// null if there is no a function
FunctionBase * function;
// parameters (name:value)
// !! CHECK ME may it should be changed to PT::Space?
ParamTab param_tab;
// this is a pointer either to the item (if exists) or to the last directory
Item * last_item;
/*
*
*
*
* variables for generating output to the client's browser
*
*
*
*/
// request status
// !! CHANGE ME it'll be better to use ordinary http result codes
Error status;
// if not empty means an address for redirecting to
// it should be url-encoded
std::wstring redirect_to;
// a redirect type
// following redirect types are supported:
// 300 Multiple Choices
// 301 Moved Permanently
// 302 Found
// 303 See Other (default)
// 307 Temporary Redirect
int redirect_type;
// send header X-LIGHTTPD-send-file with path to a file
std::wstring x_sendfile;
// send as attachment (causes generating header: content-disposition: attachment)
bool send_as_attachment;
// headers send to the client (without cookies)
PT::Space out_headers;
// cookies send to the client
// a value can be either a cookie value or the whole cookie string (with domain, date etc)
PT::Space out_cookies;
// winix can return either a text answer or a binary answer
// if send_bin_stream is true then the binary answer is sent (out_bin_stream)
// or if send_bin_stream is false then the text answer is sent
@ -148,99 +290,6 @@ struct Request
bool use_html_filter;
// raw parameters
PostTab post_tab;
PostFileTab post_file_tab;
CookieTab cookie_tab;
// html anchor (those part of URI after '#' character)
std::wstring anchor;
// environment variables
// they are not null -- when the server doesn't have such a variable
// it will be pointing into 'char_empty' which is default '\0'
const char * env_request_method;
const char * env_request_uri;
const char * env_http_cookie;
const char * env_remote_addr;
const char * env_http_host;
const char * env_http_user_agent;
const char * env_http_accept_encoding;
const char * env_fcgi_role;
const char * env_content_type;
const char * env_https;
// current IP address of the remote host (read from REMOTE_ADDR environment variable)
// (at the moment only IPv4 are supported)
int ip;
// true if the browser is Microsoft Internet Explorer
bool browser_msie;
// true if the browser is Konqueror
bool browser_konqueror;
// true if we are using encrypted connection (SSL)
bool using_ssl;
// current directory
std::vector<Item*> dir_tab;
// true if a file exists
bool is_item;
// current file (if exists)
Item item;
// current winix function
// null if there is no a function
FunctionBase * function;
// parameters (name:value)
ParamTab param_tab;
// request status
Error status;
// usually items in the current directory (depends on the function)
std::vector<Item> item_tab;
// if not empty means an address for redirecting to
// it should be url-encoded
std::wstring redirect_to;
std::string aredirect_to;
// a redirect type
// following redirect types are supported:
// 300 Multiple Choices
// 301 Moved Permanently
// 302 Found
// 303 See Other (default)
// 307 Temporary Redirect
int redirect_type;
// send header X-LIGHTTPD-send-file with path to a file
std::wstring x_sendfile;
// send as attachment (causes header: content-disposition: attachment)
bool send_as_attachment;
// this is a pointer either to the item (if exists) or to the last directory
Item * last_item;
// request start time
// Time() methods are very slow so it is better to directly use those two values
// they are set when a request starts
time_t start_time;
PT::Date start_date;
// a subdomain
// subdomain = HTTP_HOST environment variable - config->base_url
std::wstring subdomain;
// if this variable is true then winix always return 200 OK header
// when the status would be 404 (not found) or 403 (permission denied)
// default: false
@ -252,6 +301,24 @@ struct Request
bool gen_use_special_chars;
/*
additional variables used for common uses
*/
// usually items in the current directory (depends on the function)
std::vector<Item> item_tab;
Request();
void SetConfig(Config * pconfig);
void RequestStarts();
@ -261,29 +328,32 @@ struct Request
bool IsParam(const wchar_t * param_name);
bool IsParam(const std::wstring & param_name);
const std::wstring & ParamValue(const wchar_t * param_name); // returns an empty string if there is no such a parameter
const std::wstring & ParamValue(const std::wstring & param_name); // returns an empty string if there is no such a parameter
void SetCookie(const char * name, const char * value, PT::Date * expires = 0);
void SetCookie(const char * name, long value, PT::Date * expires = 0);
bool IsPostVar(const wchar_t * var);
bool IsPostVar(const std::wstring & var);
const std::wstring & PostVar(const wchar_t * var); // returns an empty string if there is no such a parameter
const std::wstring & PostVar(const std::wstring & var); // returns an empty string if there is no such a parameter
bool PostVar(const wchar_t * var, std::wstring & result);
bool PostVar(const std::wstring & var, std::wstring & result);
std::wstring * PostVarp(const wchar_t * var);
std::wstring * PostVarp(const std::wstring & var);
bool AllPostVarEmpty(); // returning true if all post vars are empty
void SendAll();
// setting a cookie
// name - cookie name (either const wchar_t, or std::wstring or PT::WTextStream)
// value - cookie value (can be everything which can be put to PT::WTextStream stream)
// the return std::wstring reference is a reference to the cookie inserted value (in out_cookies structure)
template<typename NameType, typename ValueType>
std::wstring & AddCookie(const NameType & name, const ValueType & value, PT::Date * expires = 0);
template<typename NameType, typename ValueType>
std::wstring & AddCookie(const NameType & name, const ValueType & value, PT::Date & expires);
private:
@ -303,8 +373,42 @@ private:
template<typename NameType, typename ValueType>
std::wstring & Request::AddCookie(const NameType & name, const ValueType & value, PT::Date * expires)
{
PT::WTextStream cookie;
cookie << value;
if( cookie.empty() )
cookie << L"\"\""; // cookie empty value
if( expires )
cookie << L"; expires=" << DateToStrCookie(*expires) << L" GMT";
cookie << L"; path=/; domain=" << config->base_url;
/*
!! IMPROVE ME add an option to the config
don't use '; secure' flag if you are using both sites (with SSL
and without SSL) -- with secure flag the cookie is sent only through
SSL and if you accidentally open a new window without SSL (http://)
then winix will create a new session for you and the previous session (https://)
will be lost (the session cookie will be overwritten in the client's browser)
*/
return out_cookies.Add(name, cookie);
}
template<typename NameType, typename ValueType>
std::wstring & Request::AddCookie(const NameType & name, const ValueType & value, PT::Date & expires)
{
return AddCookie(name, value, &expires);
}
#endif

View File

@ -2,7 +2,7 @@
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2011, Tomasz Sowa
* Copyright (c) 2008-2013, Tomasz Sowa
* All rights reserved.
*
*/
@ -16,6 +16,7 @@
#include "textstream/textstream.h"
// !! IMPROVE ME
// !! narazie uzywane tylko w post multi parserze
// dodac do zwyklego parsera post
#define WINIX_POSTTABLE_MAXSIZE 50
@ -43,7 +44,7 @@ typedef std::map<std::wstring, std::wstring> PostTab;
typedef std::map<std::wstring, PostFile> PostFileTab;
typedef std::vector<Param> ParamTab;
typedef std::map<std::string, std::string> CookieTab;
typedef std::map<std::wstring, std::wstring> CookieTab;
typedef PT::TextStreamBase<char, 1, 4096> BinaryPage;

View File

@ -157,7 +157,7 @@ void SessionManager::SetTemporarySession()
bool SessionManager::SetSessionFromCookie(const std::string & cookie)
bool SessionManager::SetSessionFromCookie(const std::wstring & cookie)
{
long id = Tol(cookie.c_str());
SessionContainer::Iterator s = session_tab.FindById(id);

View File

@ -88,7 +88,7 @@ private:
long CreateSessionId();
void CreateSession();
bool SetSessionFromCookie(const std::string & cookie);
bool SetSessionFromCookie(const std::wstring & cookie);
void SetTemporarySession();
// second thread