From 375604edd615baee3ef2ed1af0fa9edd065753c1 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Fri, 29 Nov 2013 21:39:23 +0000 Subject: [PATCH] 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 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 --- core/app.cpp | 236 ++++++++++++++-------------- core/app.h | 27 ++-- core/config.cpp | 7 +- core/config.h | 18 ++- core/cookieparser.h | 26 +++- core/pluginmsg.h | 11 +- core/request.cpp | 55 ++----- core/request.h | 332 ++++++++++++++++++++++++++-------------- core/requesttypes.h | 5 +- core/sessionmanager.cpp | 2 +- core/sessionmanager.h | 2 +- 11 files changed, 419 insertions(+), 302 deletions(-) diff --git a/core/app.cpp b/core/app.cpp index 57cb752..f94a50d 100755 --- a/core/app.cpp +++ b/core/app.cpp @@ -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"; - } - } -} @@ -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 diff --git a/core/app.h b/core/app.h index 6a7fd04..fc425ab 100755 --- a/core/app.h +++ b/core/app.h @@ -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 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); diff --git a/core/config.cpp b/core/config.cpp index e838a33..7e4533f 100755 --- a/core/config.cpp +++ b/core/config.cpp @@ -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); + } diff --git a/core/config.h b/core/config.h index 9b69fd1..98a54c6 100755 --- a/core/config.h +++ b/core/config.h @@ -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); diff --git a/core/cookieparser.h b/core/cookieparser.h index 3b26598..3a43139 100755 --- a/core/cookieparser.h +++ b/core/cookieparser.h @@ -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 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 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_) { diff --git a/core/pluginmsg.h b/core/pluginmsg.h index a305669..e4b868b 100755 --- a/core/pluginmsg.h +++ b/core/pluginmsg.h @@ -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 /* diff --git a/core/request.cpp b/core/request.cpp index cf90a7e..c99316c 100755 --- a/core/request.cpp +++ b/core/request.cpp @@ -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 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 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 @@ -147,100 +289,7 @@ struct Request // default: true 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 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_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_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 + std::wstring & AddCookie(const NameType & name, const ValueType & value, PT::Date * expires = 0); + + template + std::wstring & AddCookie(const NameType & name, const ValueType & value, PT::Date & expires); + + private: @@ -303,8 +373,42 @@ private: +template +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 +std::wstring & Request::AddCookie(const NameType & name, const ValueType & value, PT::Date & expires) +{ + return AddCookie(name, value, &expires); +} #endif + diff --git a/core/requesttypes.h b/core/requesttypes.h index 0ce633e..ffe7493 100755 --- a/core/requesttypes.h +++ b/core/requesttypes.h @@ -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 PostTab; typedef std::map PostFileTab; typedef std::vector ParamTab; -typedef std::map CookieTab; +typedef std::map CookieTab; typedef PT::TextStreamBase BinaryPage; diff --git a/core/sessionmanager.cpp b/core/sessionmanager.cpp index 92e9f7a..561254b 100755 --- a/core/sessionmanager.cpp +++ b/core/sessionmanager.cpp @@ -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); diff --git a/core/sessionmanager.h b/core/sessionmanager.h index f955c2f..8fa46cb 100755 --- a/core/sessionmanager.h +++ b/core/sessionmanager.h @@ -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