added: Request::header_in (Space) http input headers (without cookies)

added: config parameter: log_env_http_variables (bool) (for logging http headers)
added: support for DELETE http method, added method FunctionBase::MakeDelete()
changed: winix version incremented to 0.6.6




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@1100 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2018-04-25 19:48:47 +00:00
parent b01db89942
commit ca14b1a427
11 changed files with 169 additions and 14 deletions

View File

@ -711,6 +711,22 @@ void App::LogEnvironmentVariables()
}
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;
}
}
/*
* reading the request (without GET parameters in the URL)
@ -724,6 +740,7 @@ void App::ReadRequest()
SetSubdomain();
LogAccess();
ReadEnvHTTPVariables();
ReadPostVars();
@ -733,6 +750,9 @@ void App::ReadRequest()
if( config.log_env_variables )
LogEnvironmentVariables();
if( config.log_env_http_variables )
LogEnvironmentHTTPVariables();
CheckIE();
CheckKonqueror();
@ -759,17 +779,102 @@ void App::ReadEnvVariables()
{
SetEnv("REQUEST_METHOD", cur.request->env_request_method);
SetEnv("REQUEST_URI", cur.request->env_request_uri);
SetEnv("HTTP_COOKIE", cur.request->env_http_cookie);
SetEnv("REMOTE_ADDR", cur.request->env_remote_addr);
SetEnv("HTTP_HOST", cur.request->env_http_host);
SetEnv("HTTP_USER_AGENT", cur.request->env_http_user_agent);
SetEnv("FCGI_ROLE", cur.request->env_fcgi_role);
SetEnv("CONTENT_TYPE", cur.request->env_content_type);
SetEnv("HTTP_ACCEPT_ENCODING", cur.request->env_http_accept_encoding);
SetEnv("HTTPS", cur.request->env_https);
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;
if( IsSubStringNoCasep("HTTP_", env) )
{
env += http_prefix_len;
// cookies we have in a different table
if( !IsSubStringNoCasep("COOKIE=", env) )
{
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;
}
}
/*
* 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)
{
header_name[i] = ToSmall(env[i]);
}
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;
}
void App::ReadEnvRemoteIP()
{
@ -798,6 +903,9 @@ void App::CheckRequestMethod()
else
if( ToSmall(cur.request->env_request_method[0]) == 'h' )
cur.request->method = Request::head;
else
if( ToSmall(cur.request->env_request_method[0]) == 'd' )
cur.request->method = Request::delete_;
}
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2010-2014, Tomasz Sowa
* Copyright (c) 2010-2018, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -156,6 +156,8 @@ private:
std::string output_8bit;
BinaryPage compressed_output;
std::wstring cookie_id_string;
std::wstring http_header;
bool InitFCGI(char * sock, char * sock_user, char * sock_group);
bool InitFCGIChmodChownSocket(char * sock, char * sock_user, char * sock_group);
@ -182,9 +184,12 @@ private:
void SendAnswer();
void LogEnvironmentVariables();
void LogEnvironmentHTTPVariables();
void SetEnv(const char * name, std::wstring & env);
void ReadEnvVariables();
void ReadEnvHTTPVariables();
bool SaveEnvHTTPVariable(const char * env);
void ReadEnvRemoteIP();
void ReadPostVars();

View File

@ -147,6 +147,7 @@ void Config::AssignValues(bool stdout_is_closed)
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_env_http_variables = Bool(L"log_env_http_variables", false);
log_http_answer_headers = Bool(L"log_http_answer_headers", false);
post_file_max = Size(L"post_file_max", 8388608); // 8 MB

View File

@ -133,6 +133,9 @@ public:
// log environment variables (fastcgi environment)
bool log_env_variables;
// log environment http variables (only HTTP_* variables from fastcgi environment)
bool log_env_http_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

View File

@ -416,7 +416,7 @@ bool IsSubString(const StringType1 & short_str, const StringType2 & long_str)
template<class StringType1, class StringType2>
bool IsSubStringNoCase(const StringType1 * short_str, const StringType2 * long_str)
bool IsSubStringNoCasep(const StringType1 * short_str, const StringType2 * long_str)
{
while( *short_str && *long_str && ToSmall(*short_str) == ToSmall(*long_str) )
{
@ -430,11 +430,17 @@ bool IsSubStringNoCase(const StringType1 * short_str, const StringType2 * long_s
return false;
}
template<class StringType1, class StringType2>
bool IsSubStringNoCase(const StringType1 * short_str, const StringType2 * long_str)
{
return IsSubStringNoCasep(short_str, long_str);
}
template<class StringType1, class StringType2>
bool IsSubStringNoCase(const StringType1 & short_str, const StringType2 & long_str)
{
return IsSubStringNoCase(short_str.c_str(), long_str.c_str());
return IsSubStringNoCasep(short_str.c_str(), long_str.c_str());
}

View File

@ -96,6 +96,8 @@ void Request::Clear()
method = unknown_method;
headers_in.Clear();
out_headers.Clear();
out_cookies.Clear();

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2008-2015, Tomasz Sowa
* Copyright (c) 2008-2018, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -64,6 +64,16 @@ class FunctionBase;
struct Request
{
// how many input headers can be put to in_headers struct
static const size_t MAX_INPUT_HEADERS = 32;
// how many characters there can be in one header name
static const size_t INPUT_HEADER_NAME_MAX_LENGTH = 64;
// how many characters there can be in one header value
static const size_t INPUT_HEADER_VALUE_MAX_LENGTH = 8192;
/*
request id
is incremented for each request and is never 0
@ -97,7 +107,7 @@ struct Request
the HTTP method
!! IMPROVE ME add the rest methods here
*/
enum Method { get, post, head, unknown_method } method;
enum Method { get, post, head, delete_, unknown_method } method;
/*
@ -116,6 +126,15 @@ struct Request
PostFileTab post_file_tab;
CookieTab cookie_tab;
// input headers (without cookies)
// at the moment we are using FastCGI and HTTP headers are prefixed with 'HTTP_' string
// so we drop the prefix and change all characters to small ones
// although https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 says that there can be more
// than one http header with the same name we do not support it
// each header has a different name here, cookies we have in a different container (cookie_tab)
PT::Space headers_in;
/*
html anchor (those part of URI after '#' character)
@ -209,7 +228,7 @@ struct Request
// send as attachment (causes generating header: content-disposition: attachment)
bool send_as_attachment;
// headers send to the client (without cookies)
// headers send to the client (without cookies) (may change to headers_out?)
PT::Space out_headers;
// cookies send to the client

View File

@ -42,7 +42,7 @@ namespace Winix
#define WINIX_VER_MAJOR 0
#define WINIX_VER_MINOR 6
#define WINIX_VER_REVISION 5
#define WINIX_VER_REVISION 6

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2010-2016, Tomasz Sowa
* Copyright (c) 2010-2018, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -136,6 +136,10 @@ void FunctionBase::MakeGet()
// do nothing by default
}
void FunctionBase::MakeDelete()
{
// do nothing by default
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2010-2016, Tomasz Sowa
* Copyright (c) 2010-2018, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -84,6 +84,7 @@ public:
virtual bool HasAccess();
virtual void MakePost();
virtual void MakeGet();
virtual void MakeDelete();
void SetConfig(Config * pconfig);
void SetCur(Cur * pcur);

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2010-2016, Tomasz Sowa
* Copyright (c) 2010-2018, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -449,6 +449,12 @@ void Functions::MakeFunction()
// we should make a page similar like in a GET request but the content should not be returned only
}
else
if( cur->request->method == Request::delete_ )
{
if( cur->request->redirect_to.empty() )
cur->request->function->MakeDelete();
}
else
{
log << log1 << "Functions: unknown request method (skipping)" << logend;
}