diff options
Diffstat (limited to 'test/interactive-helper')
-rw-r--r-- | test/interactive-helper/aptwebserver.cc | 210 | ||||
-rw-r--r-- | test/interactive-helper/makefile | 2 |
2 files changed, 151 insertions, 61 deletions
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index e02caa2b3..411da0e8f 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -27,58 +27,58 @@ #include <string> #include <vector> -static char const * httpcodeToStr(int const httpcode) /*{{{*/ +static std::string httpcodeToStr(int const httpcode) /*{{{*/ { switch (httpcode) { // Informational 1xx - case 100: return "100 Continue"; - case 101: return "101 Switching Protocols"; + case 100: return _config->Find("aptwebserver::httpcode::100", "100 Continue"); + case 101: return _config->Find("aptwebserver::httpcode::101", "101 Switching Protocols"); // Successful 2xx - case 200: return "200 OK"; - case 201: return "201 Created"; - case 202: return "202 Accepted"; - case 203: return "203 Non-Authoritative Information"; - case 204: return "204 No Content"; - case 205: return "205 Reset Content"; - case 206: return "206 Partial Content"; + case 200: return _config->Find("aptwebserver::httpcode::200", "200 OK"); + case 201: return _config->Find("aptwebserver::httpcode::201", "201 Created"); + case 202: return _config->Find("aptwebserver::httpcode::202", "202 Accepted"); + case 203: return _config->Find("aptwebserver::httpcode::203", "203 Non-Authoritative Information"); + case 204: return _config->Find("aptwebserver::httpcode::204", "204 No Content"); + case 205: return _config->Find("aptwebserver::httpcode::205", "205 Reset Content"); + case 206: return _config->Find("aptwebserver::httpcode::206", "206 Partial Content"); // Redirections 3xx - case 300: return "300 Multiple Choices"; - case 301: return "301 Moved Permanently"; - case 302: return "302 Found"; - case 303: return "303 See Other"; - case 304: return "304 Not Modified"; - case 305: return "304 Use Proxy"; - case 307: return "307 Temporary Redirect"; + case 300: return _config->Find("aptwebserver::httpcode::300", "300 Multiple Choices"); + case 301: return _config->Find("aptwebserver::httpcode::301", "301 Moved Permanently"); + case 302: return _config->Find("aptwebserver::httpcode::302", "302 Found"); + case 303: return _config->Find("aptwebserver::httpcode::303", "303 See Other"); + case 304: return _config->Find("aptwebserver::httpcode::304", "304 Not Modified"); + case 305: return _config->Find("aptwebserver::httpcode::305", "305 Use Proxy"); + case 307: return _config->Find("aptwebserver::httpcode::307", "307 Temporary Redirect"); // Client errors 4xx - case 400: return "400 Bad Request"; - case 401: return "401 Unauthorized"; - case 402: return "402 Payment Required"; - case 403: return "403 Forbidden"; - case 404: return "404 Not Found"; - case 405: return "405 Method Not Allowed"; - case 406: return "406 Not Acceptable"; - case 407: return "407 Proxy Authentication Required"; - case 408: return "408 Request Time-out"; - case 409: return "409 Conflict"; - case 410: return "410 Gone"; - case 411: return "411 Length Required"; - case 412: return "412 Precondition Failed"; - case 413: return "413 Request Entity Too Large"; - case 414: return "414 Request-URI Too Large"; - case 415: return "415 Unsupported Media Type"; - case 416: return "416 Requested range not satisfiable"; - case 417: return "417 Expectation Failed"; - case 418: return "418 I'm a teapot"; + case 400: return _config->Find("aptwebserver::httpcode::400", "400 Bad Request"); + case 401: return _config->Find("aptwebserver::httpcode::401", "401 Unauthorized"); + case 402: return _config->Find("aptwebserver::httpcode::402", "402 Payment Required"); + case 403: return _config->Find("aptwebserver::httpcode::403", "403 Forbidden"); + case 404: return _config->Find("aptwebserver::httpcode::404", "404 Not Found"); + case 405: return _config->Find("aptwebserver::httpcode::405", "405 Method Not Allowed"); + case 406: return _config->Find("aptwebserver::httpcode::406", "406 Not Acceptable"); + case 407: return _config->Find("aptwebserver::httpcode::407", "407 Proxy Authentication Required"); + case 408: return _config->Find("aptwebserver::httpcode::408", "408 Request Time-out"); + case 409: return _config->Find("aptwebserver::httpcode::409", "409 Conflict"); + case 410: return _config->Find("aptwebserver::httpcode::410", "410 Gone"); + case 411: return _config->Find("aptwebserver::httpcode::411", "411 Length Required"); + case 412: return _config->Find("aptwebserver::httpcode::412", "412 Precondition Failed"); + case 413: return _config->Find("aptwebserver::httpcode::413", "413 Request Entity Too Large"); + case 414: return _config->Find("aptwebserver::httpcode::414", "414 Request-URI Too Large"); + case 415: return _config->Find("aptwebserver::httpcode::415", "415 Unsupported Media Type"); + case 416: return _config->Find("aptwebserver::httpcode::416", "416 Requested range not satisfiable"); + case 417: return _config->Find("aptwebserver::httpcode::417", "417 Expectation Failed"); + case 418: return _config->Find("aptwebserver::httpcode::418", "418 I'm a teapot"); // Server error 5xx - case 500: return "500 Internal Server Error"; - case 501: return "501 Not Implemented"; - case 502: return "502 Bad Gateway"; - case 503: return "503 Service Unavailable"; - case 504: return "504 Gateway Time-out"; - case 505: return "505 HTTP Version not supported"; - } - return NULL; + case 500: return _config->Find("aptwebserver::httpcode::500", "500 Internal Server Error"); + case 501: return _config->Find("aptwebserver::httpcode::501", "501 Not Implemented"); + case 502: return _config->Find("aptwebserver::httpcode::502", "502 Bad Gateway"); + case 503: return _config->Find("aptwebserver::httpcode::503", "503 Service Unavailable"); + case 504: return _config->Find("aptwebserver::httpcode::504", "504 Gateway Time-out"); + case 505: return _config->Find("aptwebserver::httpcode::505", "505 HTTP Version not supported"); + } + return ""; } /*}}}*/ static bool chunkedTransferEncoding(std::list<std::string> const &headers) { @@ -96,9 +96,12 @@ static void addFileHeaders(std::list<std::string> &headers, FileFd &data)/*{{{*/ contentlength << "Content-Length: " << data.FileSize(); headers.push_back(contentlength.str()); } - std::string lastmodified("Last-Modified: "); - lastmodified.append(TimeRFC1123(data.ModificationTime())); - headers.push_back(lastmodified); + if (_config->FindB("aptwebserver::support::last-modified", true) == true) + { + std::string lastmodified("Last-Modified: "); + lastmodified.append(TimeRFC1123(data.ModificationTime())); + headers.push_back(lastmodified); + } } /*}}}*/ static void addDataHeaders(std::list<std::string> &headers, std::string &data)/*{{{*/ @@ -417,22 +420,87 @@ static bool parseFirstLine(int const client, std::string const &request,/*{{{*/ // Proxies require absolute uris, so this is a simple proxy-fake option std::string const absolute = _config->Find("aptwebserver::request::absolute", "uri,path"); - if (strncmp(host.c_str(), filename.c_str(), host.length()) == 0) + if (strncmp(host.c_str(), filename.c_str(), host.length()) == 0 && APT::String::Startswith(filename, "/_config/") == false) { if (absolute.find("uri") == std::string::npos) { sendError(client, 400, request, sendContent, "Request is absoluteURI, but configured to not accept that", headers); return false; } + // strip the host from the request to make it an absolute path filename.erase(0, host.length()); + + std::string const authConf = _config->Find("aptwebserver::proxy-authorization", ""); + std::string auth = LookupTag(request, "Proxy-Authorization", ""); + if (authConf.empty() != auth.empty()) + { + if (auth.empty()) + sendError(client, 407, request, sendContent, "Proxy requires authentication", headers); + else + sendError(client, 407, request, sendContent, "Client wants to authenticate to proxy, but proxy doesn't need it", headers); + return false; + } + if (authConf.empty() == false) + { + char const * const basic = "Basic "; + if (strncmp(auth.c_str(), basic, strlen(basic)) == 0) + { + auth.erase(0, strlen(basic)); + if (auth != authConf) + { + sendError(client, 407, request, sendContent, "Proxy-Authentication doesn't match", headers); + return false; + } + } + else + { + std::list<std::string> headers; + headers.push_back("Proxy-Authenticate: Basic"); + sendError(client, 407, request, sendContent, "Unsupported Proxy-Authentication Scheme", headers); + return false; + } + } } - else if (absolute.find("path") == std::string::npos) + else if (absolute.find("path") == std::string::npos && APT::String::Startswith(filename, "/_config/") == false) { sendError(client, 400, request, sendContent, "Request is absolutePath, but configured to not accept that", headers); return false; } + if (APT::String::Startswith(filename, "/_config/") == false) + { + std::string const authConf = _config->Find("aptwebserver::authorization", ""); + std::string auth = LookupTag(request, "Authorization", ""); + if (authConf.empty() != auth.empty()) + { + if (auth.empty()) + sendError(client, 401, request, sendContent, "Server requires authentication", headers); + else + sendError(client, 401, request, sendContent, "Client wants to authenticate to server, but server doesn't need it", headers); + return false; + } + if (authConf.empty() == false) + { + char const * const basic = "Basic "; + if (strncmp(auth.c_str(), basic, strlen(basic)) == 0) + { + auth.erase(0, strlen(basic)); + if (auth != authConf) + { + sendError(client, 401, request, sendContent, "Authentication doesn't match", headers); + return false; + } + } + else + { + headers.push_back("WWW-Authenticate: Basic"); + sendError(client, 401, request, sendContent, "Unsupported Authentication Scheme", headers); + return false; + } + } + } + size_t paramspos = filename.find('?'); if (paramspos != std::string::npos) { @@ -489,6 +557,8 @@ static bool handleOnTheFlyReconfiguration(int const client, std::string const &r std::vector<std::string> parts, std::list<std::string> &headers) { size_t const pcount = parts.size(); + for (size_t i = 0; i < pcount; ++i) + parts[i] = DeQuoteString(parts[i]); if (pcount == 4 && parts[1] == "set") { _config->Set(parts[2], parts[3]); @@ -531,17 +601,24 @@ static void * handleClient(void * voidclient) /*{{{*/ { int client = *((int*)(voidclient)); std::clog << "ACCEPT client " << client << std::endl; - std::vector<std::string> messages; bool closeConnection = false; - std::list<std::string> headers; - while (closeConnection == false && ReadMessages(client, messages)) + while (closeConnection == false) { - // if we announced a closing, do the close - if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end()) + std::vector<std::string> messages; + if (ReadMessages(client, messages) == false) break; - headers.clear(); + + std::list<std::string> headers; for (std::vector<std::string>::const_iterator m = messages.begin(); m != messages.end() && closeConnection == false; ++m) { + // if we announced a closing in previous response, do the close now + if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end()) + { + closeConnection = true; + break; + } + headers.clear(); + std::clog << ">>> REQUEST from " << client << " >>>" << std::endl << *m << std::endl << "<<<<<<<<<<<<<<<<" << std::endl; std::string filename; @@ -670,9 +747,12 @@ static void * handleClient(void * voidclient) /*{{{*/ } else { - std::ostringstream contentrange; - contentrange << "Content-Range: bytes */" << filesize; - headers.push_back(contentrange.str()); + if (_config->FindB("aptwebserver::support::content-range", true) == true) + { + std::ostringstream contentrange; + contentrange << "Content-Range: bytes */" << filesize; + headers.push_back(contentrange.str()); + } sendError(client, 416, *m, sendContent, "", headers); break; } @@ -695,9 +775,16 @@ static void * handleClient(void * voidclient) /*{{{*/ else sendError(client, 404, *m, sendContent, "", headers); } + + // if we announced a closing in the last response, do the close now + if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end()) + closeConnection = true; + + if (_error->PendingError() == true) + break; _error->DumpErrors(std::cerr); - messages.clear(); } + _error->DumpErrors(std::cerr); close(client); std::clog << "CLOSE client " << client << std::endl; return NULL; @@ -709,6 +796,8 @@ int main(int const argc, const char * argv[]) CommandLine::Args Args[] = { {0, "port", "aptwebserver::port", CommandLine::HasArg}, {0, "request-absolute", "aptwebserver::request::absolute", CommandLine::HasArg}, + {0, "authorization", "aptwebserver::authorization", CommandLine::HasArg}, + {0, "proxy-authorization", "aptwebserver::proxy-authorization", CommandLine::HasArg}, {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0} @@ -794,7 +883,8 @@ int main(int const argc, const char * argv[]) std::clog << "Serving ANY file on port: " << port << std::endl; - int const slaves = _config->FindB("aptwebserver::slaves", SOMAXCONN); + int const slaves = _config->FindI("aptwebserver::slaves", SOMAXCONN); + std::cerr << "SLAVES: " << slaves << std::endl; listen(sock, slaves); /*}}}*/ diff --git a/test/interactive-helper/makefile b/test/interactive-helper/makefile index 8dc014b98..4633b78ce 100644 --- a/test/interactive-helper/makefile +++ b/test/interactive-helper/makefile @@ -39,7 +39,7 @@ include $(PROGRAM_H) #SOURCE = rpmver.cc #include $(PROGRAM_H) -# Program for testing udevcdrom +# very simple webserver for APT testing PROGRAM=aptwebserver SLIBS = -lapt-pkg -lpthread LIB_MAKES = apt-pkg/makefile |