diff --git a/winixd/core/app.cpp b/winixd/core/app.cpp index 3ee30fc..fc0cde7 100644 --- a/winixd/core/app.cpp +++ b/winixd/core/app.cpp @@ -34,13 +34,13 @@ #include #include +#include +#include #include #include #include #include #include -#include -#include #include #include #include @@ -1109,11 +1109,11 @@ void App::ParseAcceptLanguageHeader() */ void App::ReadRequest() { - ReadEnvVariables(); - ReadEnvRemoteIP(); - CheckRequestMethod(); - CheckSSL(); - SetSubdomain(); + cur.request->ReadEnvVariables(); + cur.request->ReadEnvRemoteIP(); + cur.request->CheckRequestMethod(); + cur.request->CheckSSL(); + cur.request->SetSubdomain(); LogAccess(); ReadEnvHTTPVariables(); @@ -1145,35 +1145,6 @@ void App::ReadRequest() } -void App::SetEnv(const char * name, std::wstring & env) -{ - const char * v = FCGX_GetParam(name, cur.request->fcgi_request.envp); - - if( v ) - { - pt::utf8_to_wide(v, env); - } -} - - -/* - * IMPROVE ME take it from cur.request.headers_in? - */ -void App::ReadEnvVariables() -{ - 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); - - 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); - SetEnv("HTTP_ACCEPT", cur.request->env_http_accept); - SetEnv("HTTP_ACCEPT_LANGUAGE", cur.request->env_http_accept_language); -} // reading from fastcgi env @@ -1262,69 +1233,6 @@ bool App::SaveEnvHTTPVariable(const char * env) } -void App::ReadEnvRemoteIP() -{ - const char * v = nullptr; - - if( config.check_proxy_ip_header ) - { - http_header_name = L"HTTP_"; - http_header_name += config.proxy_ip_header; - pt::to_upper_emplace(http_header_name); - - pt::wide_to_utf8(http_header_name, http_header_8bit); - v = FCGX_GetParam(http_header_8bit.c_str(), cur.request->fcgi_request.envp); - } - else - { - v = FCGX_GetParam("REMOTE_ADDR", cur.request->fcgi_request.envp); - } - - if( v ) - { - cur.request->ip = (int)inet_addr(v); - pt::utf8_to_wide(v, cur.request->ip_str); - } -} - - -void App::CheckRequestMethod() -{ - cur.request->method = Request::unknown_method; - - if( !cur.request->env_request_method.empty() ) - { - if( pt::to_lower(cur.request->env_request_method[0]) == 'g' ) - cur.request->method = Request::get; - else - if( pt::to_lower(cur.request->env_request_method[0]) == 'p' ) - cur.request->method = Request::post; - else - if( pt::to_lower(cur.request->env_request_method[0]) == 'h' ) - cur.request->method = Request::head; - else - if( pt::to_lower(cur.request->env_request_method[0]) == 'd' ) - cur.request->method = Request::delete_; - else - if( pt::to_lower(cur.request->env_request_method[0]) == 'o' ) - cur.request->method = Request::options; - } -} - - -void App::CheckSSL() -{ - // !! CHECK ME - // value "on" exists in lighttpd server - // make sure that for other servers is "on" too - - if( config.assume_connection_is_through_ssl ) - cur.request->using_ssl = true; - else - if( pt::is_equal_nc(cur.request->env_https.c_str(), L"on") ) - cur.request->using_ssl = true; -} - void App::CheckHtmx() { @@ -1338,12 +1246,6 @@ void App::CheckHtmx() } -void App::SetSubdomain() -{ - CreateSubdomain(config.base_url.c_str(), cur.request->env_http_host.c_str(), cur.request->subdomain); -} - - void App::LogAccess() { log << log1; diff --git a/winixd/core/app.h b/winixd/core/app.h index 2ec97e1..7f03e6e 100644 --- a/winixd/core/app.h +++ b/winixd/core/app.h @@ -142,7 +142,6 @@ private: std::wstring http_header_name; std::wstring http_header_value; - std::string http_header_8bit; pt::WTextStream empty_response; WinixModelConnector model_connector; // main thread model connector, each thread has its own connector @@ -198,17 +197,13 @@ private: void ReadEnvVariables(); void ReadEnvHTTPVariables(); bool SaveEnvHTTPVariable(const char * env); - void ReadEnvRemoteIP(); void ReadInputPostToBuffer(); void ParsePostJson(); void ReadPostJson(); void ReadPostVars(); void CheckIE(); void CheckKonqueror(); - void CheckRequestMethod(); - void CheckSSL(); void CheckHtmx(); - void SetSubdomain(); bool IsRequestedFrame(); void SendHeaders(); void SendCookies(); diff --git a/winixd/core/request.cpp b/winixd/core/request.cpp index 9b7d951..a8790c6 100644 --- a/winixd/core/request.cpp +++ b/winixd/core/request.cpp @@ -32,6 +32,10 @@ * */ +#include +#include +#include +#include #include "request.h" #include "log.h" #include "misc.h" @@ -245,7 +249,7 @@ void Request::Clear() aheader_value.clear(); cookie_id_string.clear(); send_data_buf.clear(); - + http_header_name.clear(); } @@ -1944,6 +1948,179 @@ void Request::LogRequestTime() } +void Request::SetEnv(const char * name, std::wstring & env) +{ + const char * v = FCGX_GetParam(name, fcgi_request.envp); + + if( v ) + { + pt::utf8_to_wide(v, env); + } +} + + +/* + * IMPROVE ME take it from cur.request.headers_in? + */ +void Request::ReadEnvVariables() +{ + SetEnv("REQUEST_METHOD", env_request_method); + SetEnv("REQUEST_URI", env_request_uri); + SetEnv("FCGI_ROLE", env_fcgi_role); + SetEnv("CONTENT_TYPE", env_content_type); + SetEnv("HTTPS", env_https); + + SetEnv("HTTP_HOST", env_http_host); + SetEnv("HTTP_USER_AGENT", env_http_user_agent); + SetEnv("HTTP_COOKIE", env_http_cookie); + SetEnv("HTTP_ACCEPT_ENCODING", env_http_accept_encoding); + SetEnv("HTTP_ACCEPT", env_http_accept); + SetEnv("HTTP_ACCEPT_LANGUAGE", env_http_accept_language); +} + + +void Request::ReadEnvRemoteIP() +{ + const char * v = nullptr; + + if( config && config->check_proxy_ip_header ) + { + http_header_8bit = "HTTP_"; + pt::wide_to_utf8(config->proxy_ip_header, http_header_8bit, false); + pt::to_upper_emplace(http_header_8bit); + v = FCGX_GetParam(http_header_8bit.c_str(), fcgi_request.envp); + } + else + { + v = FCGX_GetParam("REMOTE_ADDR", fcgi_request.envp); + } + + if( v ) + { + ip = (int)inet_addr(v); + pt::utf8_to_wide(v, ip_str); + } +} + + +Request::Method Request::CheckRequestMethod(const wchar_t * name) +{ + Method method = Request::unknown_method; + + if( pt::is_equal_nc(name, L"GET") ) + method = Request::get; + else + if( pt::is_equal_nc(name, L"HEAD") ) + method = Request::head; + else + if( pt::is_equal_nc(name, L"POST") ) + method = Request::post; + else + if( pt::is_equal_nc(name, L"PUT") ) + method = Request::put; + else + if( pt::is_equal_nc(name, L"DELETE") ) + method = Request::delete_; + else + if( pt::is_equal_nc(name, L"CONNECT") ) + method = Request::connect; + else + if( pt::is_equal_nc(name, L"OPTIONS") ) + method = Request::options; + else + if( pt::is_equal_nc(name, L"TRACE") ) + method = Request::trace; + else + if( pt::is_equal_nc(name, L"PATCH") ) + method = Request::patch; + + return method; +} + + +void Request::CheckRequestMethod() +{ + method = CheckRequestMethod(env_request_method.c_str()); +} + + +void Request::CheckSSL() +{ + // !! CHECK ME + // value "on" exists in lighttpd server + // make sure that for other servers is "on" too + + if( config && config->assume_connection_is_through_ssl ) + using_ssl = true; + else + if( pt::is_equal_nc(env_https.c_str(), L"on") ) + using_ssl = true; +} + + +void Request::SetSubdomain() +{ + if( config ) + { + CreateSubdomain(config->base_url.c_str(), env_http_host.c_str(), subdomain); + } +} + + + +void Request::PutMethodName(Request::Method method, pt::Stream & stream) +{ + switch(method) + { + case get: + stream << L"GET"; + break; + + case head: + stream << L"HEAD"; + break; + + case post: + stream << L"POST"; + break; + + case put: + stream << L"PUT"; + break; + + case delete_: + stream << L"DELETE"; + break; + + case connect: + stream << L"CONNECT"; + break; + + case options: + stream << L"OPTIONS"; + break; + + case trace: + stream << L"TRACE"; + break; + + case patch: + stream << L"PATCH"; + break; + + default: + stream << L"UNKNOWN"; + break; + } +} + + +void Request::PutMethodName(pt::Stream & stream) +{ + PutMethodName(method, stream); +} + + void Request::FinishRequest() { diff --git a/winixd/core/request.h b/winixd/core/request.h index f872b55..665f221 100644 --- a/winixd/core/request.h +++ b/winixd/core/request.h @@ -161,7 +161,7 @@ public: the HTTP method !! IMPROVE ME add the rest methods here */ - enum Method { get, post, head, delete_, options, unknown_method } method; + enum Method { get, head, post, put, delete_, connect, options, trace, patch, unknown_method } method; /* @@ -519,6 +519,20 @@ public: void FinishRequest(); + + void SetEnv(const char * name, std::wstring & env); + void ReadEnvVariables(); + void ReadEnvRemoteIP(); + + static Method CheckRequestMethod(const wchar_t * name); + void CheckRequestMethod(); + + void CheckSSL(); + void SetSubdomain(); + + static void PutMethodName(Request::Method method, pt::Stream & stream); + void PutMethodName(pt::Stream & stream); + private: Config * config; @@ -534,6 +548,8 @@ private: std::string aheader_name, aheader_value; std::wstring cookie_id_string; std::string send_data_buf; + std::wstring http_header_name; + std::string http_header_8bit; diff --git a/winixd/functions/functionbase.cpp b/winixd/functions/functionbase.cpp index ea15040..fd64ed3 100644 --- a/winixd/functions/functionbase.cpp +++ b/winixd/functions/functionbase.cpp @@ -143,13 +143,23 @@ bool FunctionBase::HasAccess() +void FunctionBase::MakeGet() +{ + // do nothing by default +} + +void FunctionBase::MakeHead() +{ + // by default call MakeGet() but do not return any content at the end of the request + MakeGet(); +} + void FunctionBase::MakePost() { // do nothing by default } - -void FunctionBase::MakeGet() +void FunctionBase::MakePut() { // do nothing by default } @@ -159,6 +169,10 @@ void FunctionBase::MakeDelete() // do nothing by default } +void FunctionBase::MakeConnect() +{ + // do nothing by default +} void FunctionBase::MakeOptions() { @@ -166,6 +180,16 @@ void FunctionBase::MakeOptions() cur->request->out_headers.add(Header::allow, L"OPTIONS, GET, HEAD, POST, DELETE"); } +void FunctionBase::MakeTrace() +{ + // do nothing by default +} + +void FunctionBase::MakePatch() +{ + // do nothing by default +} + void FunctionBase::Clear() { @@ -174,13 +198,22 @@ void FunctionBase::Clear() +void FunctionBase::ContinueMakeGet() +{ + // do nothing by default +} + +void FunctionBase::ContinueMakeHead() +{ + // do nothing by default +} + void FunctionBase::ContinueMakePost() { // do nothing by default } - -void FunctionBase::ContinueMakeGet() +void FunctionBase::ContinueMakePut() { // do nothing by default } @@ -190,11 +223,26 @@ void FunctionBase::ContinueMakeDelete() // do nothing by default } +void FunctionBase::ContinueMakeConnect() +{ + // do nothing by default +} + void FunctionBase::ContinueMakeOptions() { // do nothing by default } +void FunctionBase::ContinueMakeTrace() +{ + // do nothing by default +} + +void FunctionBase::ContinueMakePatch() +{ + // do nothing by default +} + } // namespace Winix diff --git a/winixd/functions/functionbase.h b/winixd/functions/functionbase.h index 1cb5e2e..4bf5dd4 100644 --- a/winixd/functions/functionbase.h +++ b/winixd/functions/functionbase.h @@ -110,20 +110,32 @@ public: virtual void Finish(); virtual bool HasAccess(); - virtual void MakePost(); + virtual void MakeGet(); + virtual void MakeHead(); + virtual void MakePost(); + virtual void MakePut(); virtual void MakeDelete(); + virtual void MakeConnect(); virtual void MakeOptions(); + virtual void MakeTrace(); + virtual void MakePatch(); + virtual void Clear(); /* * called from the jobs thread * objects are locked */ - virtual void ContinueMakePost(); virtual void ContinueMakeGet(); + virtual void ContinueMakeHead(); + virtual void ContinueMakePost(); + virtual void ContinueMakePut(); virtual void ContinueMakeDelete(); + virtual void ContinueMakeConnect(); virtual void ContinueMakeOptions(); + virtual void ContinueMakeTrace(); + virtual void ContinueMakePatch(); //void SetConfig(Config * pconfig); diff --git a/winixd/functions/functions.cpp b/winixd/functions/functions.cpp index 01e02a3..441248c 100644 --- a/winixd/functions/functions.cpp +++ b/winixd/functions/functions.cpp @@ -462,57 +462,72 @@ void Functions::MakeFunction() { if( !cur->request->function ) { - cur->request->status = WINIX_ERR_NO_FUNCTION; - log << log1 << "Functions: no function (neither cat nor ls)" << logend; + cur->request->http_status = Header::status_500_internal_server_error; // or 404? (404 was originally) + log << log1 << "Functions: no function to call" << logend; return; } - if( !system->DirsHaveReadExecPerm() || - !system->HasReadExecAccess(cur->request->function->fun) || + if( !system->DirsHaveReadExecPerm() || + !system->HasReadExecAccess(cur->request->function->fun) || !cur->request->function->HasAccess() ) { - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + cur->request->http_status = Header::status_403_forbidden; + return; + } + + if( !cur->request->redirect_to.empty() ) + { + log << log3 << "Functions: there is a redirect_to set so I do not call the function" << logend; return; } if( cur->request->method == Request::get ) { - if( cur->request->redirect_to.empty() ) - cur->request->function->MakeGet(); - } - else - if( cur->request->method == Request::post ) - { - // we don't use post with redirecting (the post variables would be lost) - - if( cur->request->redirect_to.empty() ) - cur->request->function->MakePost(); - else - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + cur->request->function->MakeGet(); } else if( cur->request->method == Request::head ) { - // do nothing - - // !! IMPROVE ME - // we should make a page similar like in a GET request but the content should not be returned only + cur->request->function->MakeHead(); + } + else + if( cur->request->method == Request::post ) + { + cur->request->function->MakePost(); + } + else + if( cur->request->method == Request::put ) + { + cur->request->function->MakePut(); } else if( cur->request->method == Request::delete_ ) { - if( cur->request->redirect_to.empty() ) - cur->request->function->MakeDelete(); + cur->request->function->MakeDelete(); + } + else + if( cur->request->method == Request::connect ) + { + cur->request->function->MakeConnect(); } else if( cur->request->method == Request::options ) { - if( cur->request->redirect_to.empty() ) - cur->request->function->MakeOptions(); + cur->request->function->MakeOptions(); + } + else + if( cur->request->method == Request::trace ) + { + cur->request->function->MakeTrace(); + } + else + if( cur->request->method == Request::patch ) + { + cur->request->function->MakePatch(); } else { - log << log1 << "Functions: unknown request method (skipping)" << logend; + log << log1 << "Functions: I cannot call a function, an unknown request method (skipping)" << logend; } } @@ -521,57 +536,70 @@ void Functions::ContinueMakeFunction() { if( !cur->request->function ) { - cur->request->status = WINIX_ERR_NO_FUNCTION; - log << log1 << "Functions: no function (neither cat nor ls)" << logend; + cur->request->http_status = Header::status_500_internal_server_error; // or 404? (404 was originally) + log << log1 << "Functions: no function to call in the request continuation" << logend; return; } -// if( !system->DirsHaveReadExecPerm() || -// !system->HasReadExecAccess(cur->request->function->fun) || -// !cur->request->function->HasAccess() ) -// { -// cur->request->status = WINIX_ERR_PERMISSION_DENIED; -// return; -// } + if( !system->DirsHaveReadExecPerm() || + !system->HasReadExecAccess(cur->request->function->fun) || + !cur->request->function->HasAccess() ) + { + cur->request->http_status = Header::status_403_forbidden; + return; + } + + log << log4 << "Functions: continuing method "; + cur->request->PutMethodName(log); + log << " for request " << cur->request << " for function " << cur->request->function->fun.url << logend; if( cur->request->method == Request::get ) { - log << log4 << "Functions: continuing method get for request " << cur->request - << " for function " << cur->request->function->fun.url << logend; cur->request->function->ContinueMakeGet(); } else - if( cur->request->method == Request::post ) - { - log << log4 << "Functions: continuing method post for request " << cur->request - << " for function " << cur->request->function->fun.url << logend; - cur->request->function->ContinueMakePost(); - } - else if( cur->request->method == Request::head ) { - // do nothing - - // !! IMPROVE ME - // we should make a page similar like in a GET request but the content should not be returned only + cur->request->function->ContinueMakeHead(); + } + else + if( cur->request->method == Request::post ) + { + cur->request->function->ContinueMakePost(); + } + else + if( cur->request->method == Request::put ) + { + cur->request->function->ContinueMakePut(); } else if( cur->request->method == Request::delete_ ) { - log << log4 << "Functions: continuing method delete for request " << cur->request - << " for function " << cur->request->function->fun.url << logend; cur->request->function->ContinueMakeDelete(); } else + if( cur->request->method == Request::connect ) + { + cur->request->function->ContinueMakeConnect(); + } + else if( cur->request->method == Request::options ) { - log << log4 << "Functions: continuing method options for request " << cur->request - << " for function " << cur->request->function->fun.url << logend; cur->request->function->ContinueMakeOptions(); } else + if( cur->request->method == Request::trace ) { - log << log1 << "Functions: cannot continue a request, unknown request method (skipping)" << logend; + cur->request->function->ContinueMakeTrace(); + } + else + if( cur->request->method == Request::patch ) + { + cur->request->function->ContinueMakePatch(); + } + else + { + log << log1 << "Functions: I cannot continue a request, an unknown request method (skipping)" << logend; } }