changed: now we do not use std::string and char* in the Winix API

everywhere we are using std::wstring and wchar_t*
         (std::string and char* is used only locally in some places
         especially when creating a path to OS file system etc.)
added:   to the special thread when winix closes:
         a write function for curl: FetchPageOnExitCurlCallback()
         without this function the curl library will print
         the page's content to the standart output
changed: TextStream<> class from core can make
         UTF8<->wide strings conversions
removed: from config: utf8 option
         now winix expects UTF8 from the user's input (html forms, url-es)
         and outputs strings in the UTF8 format




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@965 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
2014-10-09 20:44:56 +00:00
parent 4abf6642f7
commit 8196fb77d1
74 changed files with 1911 additions and 1612 deletions

View File

@@ -114,12 +114,70 @@ App::App()
bool App::InitFCGI(char * sock, char * sock_user, char * sock_group)
{
if( !WideToUTF8(config.fcgi_socket, sock, WINIX_OS_PATH_SIZE) )
return false;
if( !WideToUTF8(config.fcgi_socket_user, sock_user, WINIX_OS_USERNAME_SIZE) )
return false;
if( !WideToUTF8(config.fcgi_socket_group, sock_group, WINIX_OS_USERNAME_SIZE) )
return false;
return true;
}
/*
* chmod and chown of the socket are set before winix drops privileges
*/
bool App::InitFCGIChmodChownSocket(char * sock, char * sock_user, char * sock_group)
{
if( chmod(sock, config.fcgi_socket_chmod) < 0 )
{
log << log1 << "App: I cannot chmod a FastCGI socket, check fcgi_socket_chmod in the config" << logend;
return false;
}
passwd * pw = getpwnam(sock_user);
if( !pw )
{
log << log1 << "App: there is no a user: " << config.fcgi_socket_user << logend;
return false;
}
group * gr = getgrnam(sock_group);
if( !gr )
{
log << log1 << "App: there is no a group: " << config.fcgi_socket_group << logend;
return false;
}
if( chown(sock, pw->pw_uid, gr->gr_gid) < 0 )
{
log << log1 << "App: I cannot chown a FastCGI socket, check fcgi_socket_user "
<< "and fcgi_socket_group in the config" << logend;
return false;
}
return true;
}
bool App::InitFCGI()
{
const char * sock = config.fcgi_socket.c_str();
unlink(sock);
char sock[WINIX_OS_PATH_SIZE];
char sock_user[WINIX_OS_USERNAME_SIZE];
char sock_group[WINIX_OS_USERNAME_SIZE];
fcgi_socket = FCGX_OpenSocket(sock, 100); // !! dodac 100 do konfiga
if( !InitFCGI(sock, sock_user, sock_group) )
return false;
unlink(sock);
fcgi_socket = FCGX_OpenSocket(sock, config.fcgi_socket_listen);
if( fcgi_socket < 0 )
{
@@ -128,25 +186,9 @@ bool App::InitFCGI()
}
log << log3 << "App: FastCGI socket number: " << fcgi_socket << logend;
chmod(sock, config.fcgi_socket_chmod);
passwd * pw = getpwnam(config.fcgi_socket_user.c_str());
if( !pw )
{
log << log1 << "App: there is no user: " << config.fcgi_socket_user << logend;
if( !InitFCGIChmodChownSocket(sock, sock_user, sock_group) )
return false;
}
group * gr = getgrnam(config.fcgi_socket_group.c_str());
if( !gr )
{
log << log1 << "App: there is no group: " << config.fcgi_socket_group << logend;
return false;
}
chown(sock, pw->pw_uid, gr->gr_gid);
if( FCGX_Init() != 0 )
{
@@ -185,12 +227,9 @@ bool App::Init()
CreateStaticTree();
post_parser.UTF8(config.utf8);
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;
@@ -218,7 +257,7 @@ void App::BaseUrlRedirect(int code, bool add_subdomain)
}
cur.request->redirect_to += config.base_url;
AssignString(cur.request->env_request_uri, cur.request->redirect_to, false);
cur.request->redirect_to += cur.request->env_request_uri;
// cur.request->env_request_uri should not be UrlEncoded because it contains slashes
cur.request->redirect_type = code;
}
@@ -241,7 +280,7 @@ bool App::BaseUrlRedirect()
if( cur.request->method == Request::post )
return false;
if( Equal(config.base_url.c_str(), cur.request->env_http_host) )
if( config.base_url == cur.request->env_http_host )
return false;
BaseUrlRedirect(config.base_url_redirect_code, false);
@@ -345,7 +384,28 @@ void App::ProcessRequestThrow()
}
plugin.Call(WINIX_SESSION_CHANGED);
functions.Parse(); // parsing directories,files,functions and parameters
if( cur.request->env_request_uri.size() <= WINIX_URL_MAX_SIZE )
{
functions.Parse(); // parsing directories, files, functions and parameters
}
else
{
/*
* IMPROVE ME
* it will not have the root directory set
* so as a response only a blank page is shown
* (root directory is set in funcions.Parse())
*
* IMPROVE ME
* we can add a better return code (http status):
* http://www.ietf.org/rfc/rfc2616.txt
* "A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle"
*
*/
cur.request->status = WINIX_ERR_PERMISSION_DENIED;
log << log1 << "App: the URL is too long: " << cur.request->env_request_uri.size() << logend;
}
cur.mount = system.mounts.CalcCurMount();
@@ -637,17 +697,21 @@ void App::LogEnvironmentVariables()
/*
* reading the request (without GET parameters in the URL)
*/
void App::ReadRequest()
{
ReadEnvVariables();
ReadEnvRemoteIP();
CheckRequestMethod();
CheckSSL();
SetSubdomain();
LogAccess();
ReadGetPostVars();
ReadPostVars();
cookie_parser.Parse(cur.request->env_http_cookie, cur.request->cookie_tab);
accept_encoding_parser.ParseAndLog(cur.request->env_http_accept_encoding);
@@ -663,51 +727,63 @@ void App::ReadRequest()
void App::SetEnv(const char * & env, const char * name)
void App::SetEnv(const char * name, std::wstring & env)
{
const char * v = FCGX_GetParam(name, fcgi_request.envp);
const char * v = FCGX_GetParam(name, fcgi_request.envp);
if( v )
env = v;
// by default env is set to an empty string (in cur.request->Clear() method)
{
PT::UTF8ToWide(v, env);
}
}
void App::ReadEnvVariables()
{
// we store that values because FCGX_GetParam has O(n) complexity
// with this variables (env_*) we have O(1)
SetEnv(cur.request->env_request_method, "REQUEST_METHOD"); // !! mozna nie uzywac tego, teraz mamy w strukturze fcgi_request
SetEnv(cur.request->env_request_uri, "REQUEST_URI");
SetEnv(cur.request->env_http_cookie, "HTTP_COOKIE");
SetEnv(cur.request->env_remote_addr, "REMOTE_ADDR");
SetEnv(cur.request->env_http_host, "HTTP_HOST");
SetEnv(cur.request->env_http_user_agent, "HTTP_USER_AGENT");
SetEnv(cur.request->env_fcgi_role, "FCGI_ROLE");
SetEnv(cur.request->env_content_type, "CONTENT_TYPE");
SetEnv(cur.request->env_http_accept_encoding, "HTTP_ACCEPT_ENCODING");
SetEnv(cur.request->env_https, "HTTPS");
cur.request->ip = (int)inet_addr(cur.request->env_remote_addr);
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);
}
void App::ReadEnvRemoteIP()
{
const char * v = FCGX_GetParam("REMOTE_ADDR", fcgi_request.envp);
if( v )
{
cur.request->ip = (int)inet_addr(v);
}
}
void App::CheckRequestMethod()
{
cur.request->method = Request::unknown_method;
if( ToSmall(cur.request->env_request_method[0]) == 'g' )
cur.request->method = Request::get;
else
if( ToSmall(cur.request->env_request_method[0]) == 'p' )
cur.request->method = Request::post;
else
if( ToSmall(cur.request->env_request_method[0]) == 'h' )
cur.request->method = Request::head;
if( !cur.request->env_request_method.empty() )
{
if( ToSmall(cur.request->env_request_method[0]) == 'g' )
cur.request->method = Request::get;
else
if( ToSmall(cur.request->env_request_method[0]) == 'p' )
cur.request->method = Request::post;
else
if( ToSmall(cur.request->env_request_method[0]) == 'h' )
cur.request->method = Request::head;
}
}
@@ -718,14 +794,14 @@ void App::CheckSSL()
// value "on" exists in lighttpd server
// make sure that for other servers is "on" too
if( EqualNoCase(cur.request->env_https, "on") )
if( EqualNoCase(cur.request->env_https.c_str(), L"on") )
cur.request->using_ssl = true;
}
void App::SetSubdomain()
{
CreateSubdomain(config.base_url.c_str(), cur.request->env_http_host, cur.request->subdomain);
CreateSubdomain(config.base_url.c_str(), cur.request->env_http_host.c_str(), cur.request->subdomain);
}
@@ -747,15 +823,11 @@ void App::LogAccess()
void App::ReadGetPostVars()
void App::ReadPostVars()
{
// get parameters we have always
//get_parser.Parse(cur.request->env_request_uri, cur.request->get_tab);
if( cur.request->method == Request::post )
{
if( IsSubStringNoCase("multipart/form-data", cur.request->env_content_type) )
if( IsSubStringNoCase(L"multipart/form-data", cur.request->env_content_type.c_str()) )
{
log << log3 << "App: post content type: multipart/form-data" << logend;
post_multi_parser.Parse(fcgi_request.in, cur.request->post_tab, cur.request->post_file_tab);
@@ -772,24 +844,16 @@ void App::ReadGetPostVars()
void App::CheckIE()
{
const char * msie = strstr(cur.request->env_http_user_agent, "MSIE");
if( msie )
cur.request->browser_msie = true;
else
cur.request->browser_msie = false;
size_t msie = cur.request->env_http_user_agent.find(L"MSIE");
cur.request->browser_msie = (msie != std::wstring::npos);
}
void App::CheckKonqueror()
{
const char * kon = strstr(cur.request->env_http_user_agent, "Konqueror");
if( kon )
cur.request->browser_konqueror = true;
else
cur.request->browser_konqueror = false;
size_t kon = cur.request->env_http_user_agent.find(L"Konqueror");
cur.request->browser_konqueror = (kon != std::wstring::npos);
}
@@ -875,7 +939,7 @@ bool App::PrepareHeadersStaticCreateResource(PT::WTextStream & out_path)
}
size_t how_many_dirs = system.dirs.DirLevel(dir->id);
const char * path = SkipDirs(cur.request->env_request_uri, how_many_dirs);
const wchar_t * path = SkipDirs(cur.request->env_request_uri.c_str(), how_many_dirs);
// the path begins with a slash only if how_many_dirs is zero
while( *path == '/' )
@@ -954,7 +1018,7 @@ void App::PrepareHeaderContentType()
}
}
if( value && config.utf8 )
if( value )
*value += L"; charset=UTF-8";
}
}
@@ -1066,11 +1130,19 @@ void App::SendHeaders()
FCGX_PutS("\r\n", fcgi_request.out);
if( config.log_http_answer_headers )
log << "HTTP Header: " << aheader_name << ": " << aheader_value << logend;
log << log1 << "HTTP Header: " << aheader_name << ": " << aheader_value << logend;
}
}
template<class RawType>
DbTextStream::RawText<RawType> R(const RawType & par)
{
return DbTextStream::RawText<RawType>(par);
}
void App::SendCookies()
{
PT::Space::TableSingle::iterator i;
@@ -1090,7 +1162,7 @@ void App::SendCookies()
FCGX_PutS("\r\n", fcgi_request.out);
if( config.log_http_answer_headers )
log << "HTTP Header: " << "Set-Cookie: " << aheader_name << "=" << aheader_value << logend;
log << log1 << "HTTP Header: Set-Cookie: " << aheader_name << "=" << aheader_value << logend;
}
}
@@ -1296,10 +1368,7 @@ size_t output_size = 0;
SelectCompression(source->length(), compressing, compress_encoding);
if( config.utf8 )
PT::WideToUTF8(*source, output_8bit);
else
AssignString(*source, output_8bit);
PT::WideToUTF8(*source, output_8bit);
// !! IMPROVE ME add to log the binary stream as well
if( config.log_server_answer )
@@ -1525,13 +1594,27 @@ void App::LogUserGroups()
bool App::DropPrivileges(const std::string & user, uid_t uid, gid_t gid, bool additional_groups)
bool App::DropPrivileges(char * user, char * group)
{
if( !WideToUTF8(config.user, user, WINIX_OS_USERNAME_SIZE) )
return false;
if( !WideToUTF8(config.group, group, WINIX_OS_USERNAME_SIZE) )
return false;
return true;
}
bool App::DropPrivileges(const char * user, uid_t uid, gid_t gid, bool additional_groups)
{
if( additional_groups )
{
if( initgroups(user.c_str(), gid) < 0 )
if( initgroups(user, gid) < 0 )
{
log << log1 << "App: I can't init groups for user: " << user << logend;
log << log1 << "App: I can't init groups for a user: " << user << logend;
return false;
}
}
@@ -1545,7 +1628,7 @@ bool App::DropPrivileges(const std::string & user, uid_t uid, gid_t gid, bool ad
}
// for setting real and saved gid too
if( setgid(gid) )
if( setgid(gid) < 0 )
{
log << log1 << "App: I can't change real and saved gid" << logend;
return false;
@@ -1568,8 +1651,12 @@ return true;
}
bool App::DropPrivileges()
{
char user_name[WINIX_OS_USERNAME_SIZE];
char group_name[WINIX_OS_USERNAME_SIZE];
if( getuid()!=0 && geteuid()!=0 )
return true;
@@ -1577,20 +1664,23 @@ bool App::DropPrivileges()
if( config.user.empty() )
{
log << log1 << "App: you should specify user name in the config file "
log << log1 << "App: in the config file you should specify a user name and a group "
<< "to which I have to drop privileges" << logend;
return false;
}
if( config.group.empty() )
{
log << log1 << "App: you should specify group name in the config file "
log << log1 << "App: you should specify a group name in the config file "
<< "to which I have to drop privileges" << logend;
return false;
}
passwd * p = getpwnam(config.user.c_str());
group * g = getgrnam(config.group.c_str());
if( !DropPrivileges(user_name, group_name) )
return false;
passwd * p = getpwnam(user_name);
group * g = getgrnam(group_name);
if( !p )
{
@@ -1604,7 +1694,7 @@ bool App::DropPrivileges()
return false;
}
if( !DropPrivileges(config.user, p->pw_uid, g->gr_gid, config.additional_groups) )
if( !DropPrivileges(user_name, p->pw_uid, g->gr_gid, config.additional_groups) )
return false;
return true;
@@ -1674,6 +1764,16 @@ void App::WaitForThreads()
size_t App::FetchPageOnExitCurlCallback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
/*
* without this function the curl library will print the page's content
* to the standart output
*/
return size * nmemb;
}
void App::FetchPageOnExit()
{
// stupid trick to break FCGX_Accept_r() function
@@ -1690,7 +1790,15 @@ void App::FetchPageOnExit()
curl_easy_setopt(curl, CURLOPT_URL, url_to_fetch_on_exit.c_str());
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_perform(curl);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, FetchPageOnExitCurlCallback);
if( curl_easy_perform(curl) != 0 )
{
Lock();
log << log1 << "App: I cannot correctly fetch a page from the special thread" << logend << logsave;
Unlock();
}
curl_easy_cleanup(curl);
}
}