From fdfe95e7928c9e8aac77c71b5c26f84426dd3971 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Sun, 16 Oct 2011 16:45:55 +0200 Subject: [PATCH] Fixed some issues in HTTP, added GET param support, fixed a bug, etc... lots of maintenaince. --- util/http_parser.cpp | 74 +++++++++++++++++++++++++------------------- util/http_parser.h | 3 +- util/proc.cpp | 25 +++++++++++++++ util/proc.h | 3 ++ 4 files changed, 72 insertions(+), 33 deletions(-) diff --git a/util/http_parser.cpp b/util/http_parser.cpp index 274cb3c3..da800130 100644 --- a/util/http_parser.cpp +++ b/util/http_parser.cpp @@ -14,9 +14,9 @@ void HTTP::Parser::Clean(){ method = "GET"; url = "/"; protocol = "HTTP/1.1"; - body = ""; + body.clear(); length = 0; - HTTPbuffer = ""; + HTTPbuffer.clear(); headers.clear(); vars.clear(); } @@ -172,7 +172,10 @@ bool HTTP::Parser::parse(){ if (f != std::string::npos){url = tmpA.substr(0, f); tmpA.erase(0, f+1);} f = tmpA.find(' '); if (f != std::string::npos){protocol = tmpA.substr(0, f); tmpA.erase(0, f+1);} - /// \todo Include GET variable parsing? + if (url.find('?') != std::string::npos){ + std::string queryvars = url.substr(url.find('?')+1); + parseVars(queryvars); //parse GET variables + } }else{ if (tmpA.size() == 0){ seenHeaders = true; @@ -191,22 +194,7 @@ bool HTTP::Parser::parse(){ if (HTTPbuffer.length() >= length){ body = HTTPbuffer.substr(0, length); HTTPbuffer.erase(0, length); - std::string tmppost = body; - std::string varname; - std::string varval; - while (tmppost.find('=') != std::string::npos){ - size_t found = tmppost.find('='); - varname = urlunescape((char*)tmppost.substr(0, found).c_str()); - tmppost.erase(0, found+1); - found = tmppost.find('&'); - varval = urlunescape((char*)tmppost.substr(0, found).c_str()); - SetVar(varname, varval); - if (found == std::string::npos){ - tmppost.clear(); - }else{ - tmppost.erase(0, found+1); - } - } + parseVars(body); //parse POST variables return true; }else{ return false; @@ -229,6 +217,26 @@ void HTTP::Parser::SendResponse(Socket::Connection & conn, std::string code, std conn.write(tmp); } +/// Parses GET or POST-style variable data. +/// Saves to internal variable structure using HTTP::Parser::SetVar. +void HTTP::Parser::parseVars(std::string & data){ + std::string varname; + std::string varval; + while (data.find('=') != std::string::npos){ + size_t found = data.find('='); + varname = urlunescape(data.substr(0, found)); + data.erase(0, found+1); + found = data.find('&'); + varval = urlunescape(data.substr(0, found)); + SetVar(varname, varval); + if (found == std::string::npos){ + data.clear(); + }else{ + data.erase(0, found+1); + } + } +} + /// Sends data as HTTP/1.1 bodypart to conn. /// HTTP/1.1 chunked encoding is automatically applied if needed. /// \param conn The Socket::Connection to send the part over. @@ -257,24 +265,26 @@ void HTTP::Parser::SendBodyPart(Socket::Connection & conn, std::string bodypart) } } -/// Unescapes URLencoded C-strings to a std::string. -/// This function *will* destroy the input data! -std::string HTTP::Parser::urlunescape(char *s){ - char *p; - for (p = s; *s != '\0'; ++s){ - if (*s == '%'){ - if (*++s != '\0'){ - *p = unhex(*s) << 4; +/// Unescapes URLencoded std::strings. +std::string HTTP::Parser::urlunescape(std::string in){ + std::string out; + for (unsigned int i = 0; i < in.length(); ++i){ + if (in[i] == '%'){ + char tmp = 0; + ++i; + if (i < in.length()){ + tmp = unhex(in[i]) << 4; } - if (*++s != '\0'){ - *p++ += unhex(*s); + ++i; + if (i < in.length()){ + tmp += unhex(in[i]); } + out += tmp; } else { - if (*s == '+'){*p++ = ' ';}else{*p++ = *s;} + if (in[i] == '+'){out += ' ';}else{out += in[i];} } } - *p = '\0'; - return std::string(s); + return out; } /// Helper function for urlunescape. diff --git a/util/http_parser.h b/util/http_parser.h index 542c06e6..a38b94e1 100644 --- a/util/http_parser.h +++ b/util/http_parser.h @@ -30,7 +30,7 @@ namespace HTTP{ void SendBodyPart(Socket::Connection & conn, std::string bodypart); void Clean(); bool CleanForNext(); - std::string urlunescape(char *s); ///< Unescapes URLencoded C-strings to a std::string. + std::string urlunescape(std::string in); std::string body; std::string method; std::string url; @@ -40,6 +40,7 @@ namespace HTTP{ bool seenHeaders; bool seenReq; bool parse(); + void parseVars(std::string & data); std::string HTTPbuffer; std::map headers; std::map vars; diff --git a/util/proc.cpp b/util/proc.cpp index b5257065..bfcd3210 100644 --- a/util/proc.cpp +++ b/util/proc.cpp @@ -10,10 +10,35 @@ #if DEBUG >= 1 #include #endif +#include +#include std::map Util::Procs::plist; bool Util::Procs::handler_set = false; +/// Sets the current process' running user +void Util::setUser(std::string username){ + if (username != "root"){ + struct passwd * user_info = getpwnam(username.c_str()); + if (!user_info){ + #if DEBUG >= 1 + fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str()); + #endif + return 1; + }else{ + if (setuid(user_info->pw_uid) != 0){ + #if DEBUG >= 1 + fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str()); + #endif + }else{ + #if DEBUG >= 3 + fprintf(stderr, "Changed user to %s\n", username.c_str()); + #endif + } + } + } +} + /// Used internally to capture child signals and update plist. void Util::Procs::childsig_handler(int signum){ if (signum != SIGCHLD){return;} diff --git a/util/proc.h b/util/proc.h index a74d75bd..4b117f0c 100644 --- a/util/proc.h +++ b/util/proc.h @@ -27,4 +27,7 @@ namespace Util{ static pid_t getPid(std::string name); static std::string getName(pid_t name); }; + + static setUser(std::string user); + };