From 6beca0eb8bfc105ba25e140e8ca4e07e78d097e7 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 15 Sep 2013 22:54:04 +0200 Subject: access _config via GET requests in the webserver Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 74 +++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index fde95fec9..7134b37bc 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -156,14 +156,28 @@ void sendError(int const client, int const httpcode, std::string const &request, std::string response(""); response.append(httpcodeToStr(httpcode)).append(""); response.append("

").append(httpcodeToStr(httpcode)).append("

"); - if (error.empty() == false) - response.append("

Error: ").append(error).append("

"); - response.append("This error is a result of the request:
");
+   if (httpcode != 200)
+   {
+      if (error.empty() == false)
+	 response.append("

Error: ").append(error).append("

"); + response.append("This error is a result of the request:
");
+   }
+   else
+   {
+      if (error.empty() == false)
+	 response.append("

Success: ").append(error).append("

"); + response.append("The successfully executed operation was requested by:
");
+   }
    response.append(request).append("
"); addDataHeaders(headers, response); sendHead(client, httpcode, headers); if (content == true) sendData(client, response); +} +void sendSuccess(int const client, std::string const &request, + bool content, std::string const &error = "") +{ + sendError(client, 200, request, content, error); } /*}}}*/ void sendRedirect(int const client, int const httpcode, std::string const &uri,/*{{{*/ @@ -365,6 +379,49 @@ bool parseFirstLine(int const client, std::string const &request, /*{{{*/ return true; } /*}}}*/ +bool handleOnTheFlyReconfiguration(int const client, std::string const &request, std::vector const &parts)/*{{{*/ +{ + size_t const pcount = parts.size(); + if (pcount == 4 && parts[1] == "set") + { + _config->Set(parts[2], parts[3]); + sendSuccess(client, request, true, "Option '" + parts[2] + "' was set to '" + parts[3] + "'!"); + return true; + } + else if (pcount == 4 && parts[1] == "find") + { + std::list headers; + std::string response = _config->Find(parts[2], parts[3]); + addDataHeaders(headers, response); + sendHead(client, 200, headers); + sendData(client, response); + return true; + } + else if (pcount == 3 && parts[1] == "find") + { + std::list headers; + if (_config->Exists(parts[2]) == true) + { + std::string response = _config->Find(parts[2]); + addDataHeaders(headers, response); + sendHead(client, 200, headers); + sendData(client, response); + return true; + } + sendError(client, 404, request, "Requested Configuration option doesn't exist."); + return false; + } + else if (pcount == 3 && parts[1] == "clear") + { + _config->Clear(parts[2]); + sendSuccess(client, request, true, "Option '" + parts[2] + "' was cleared."); + return true; + } + + sendError(client, 400, request, true, "Unknown on-the-fly configuration request"); + return false; +} + /*}}}*/ int main(int const argc, const char * argv[]) { CommandLine::Args Args[] = { @@ -475,6 +532,17 @@ int main(int const argc, const char * argv[]) if (parseFirstLine(client, *m, filename, sendContent, closeConnection) == false) continue; + // special webserver command request + if (filename.length() > 1 && filename[0] == '_') + { + std::vector parts = VectorizeString(filename, '/'); + if (parts[0] == "_config") + { + handleOnTheFlyReconfiguration(client, *m, parts); + continue; + } + } + // string replacements in the requested filename ::Configuration::Item const *Replaces = _config->Tree("aptwebserver::redirect::replace"); if (Replaces != NULL) -- cgit v1.2.3-70-g09d2 From 14c84d021d82335255275f1eabf3a856bde4df07 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 16 Sep 2013 00:02:21 +0200 Subject: add Range and If-Range support in the webserver Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 64 ++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 7134b37bc..4dae342dd 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -100,8 +100,13 @@ bool sendHead(int const client, int const httpcode, std::list &head std::string response("HTTP/1.1 "); response.append(httpcodeToStr(httpcode)); headers.push_front(response); + _config->Set("APTWebserver::Last-Status-Code", httpcode); - headers.push_back("Server: APT webserver"); + std::stringstream buffer; + _config->Dump(buffer, "aptwebserver::response-header", "%t: %v%n", false); + std::vector addheaders = VectorizeString(buffer.str(), '\n'); + for (std::vector::const_iterator h = addheaders.begin(); h != addheaders.end(); ++h) + headers.push_back(*h); std::string date("Date: "); date.append(TimeRFC1123(time(NULL))); @@ -512,6 +517,9 @@ int main(int const argc, const char * argv[]) listen(sock, 1); /*}}}*/ + _config->CndSet("aptwebserver::response-header::Server", "APT webserver"); + _config->CndSet("aptwebserver::response-header::Accept-Ranges", "bytes"); + std::vector messages; int client; while ((client = accept(sock, NULL, NULL)) != -1) @@ -600,6 +608,60 @@ int main(int const argc, const char * argv[]) } } + if (_config->FindB("aptwebserver::support::range", true) == true) + condition = LookupTag(*m, "Range", ""); + else + condition.clear(); + if (condition.empty() == false && strncmp(condition.c_str(), "bytes=", 6) == 0) + { + time_t cache; + std::string ifrange; + if (_config->FindB("aptwebserver::support::if-range", true) == true) + ifrange = LookupTag(*m, "If-Range", ""); + bool validrange = (ifrange.empty() == true || + (RFC1123StrToTime(ifrange.c_str(), cache) == true && + cache <= data.ModificationTime())); + + // FIXME: support multiple byte-ranges (APT clients do not do this) + if (condition.find(',') == std::string::npos) + { + size_t start = 6; + unsigned long long filestart = strtoull(condition.c_str() + start, NULL, 10); + // FIXME: no support for last-byte-pos being not the end of the file (APT clients do not do this) + size_t dash = condition.find('-') + 1; + unsigned long long fileend = strtoull(condition.c_str() + dash, NULL, 10); + unsigned long long filesize = data.FileSize(); + if ((fileend == 0 || (fileend == filesize && fileend >= filestart)) && + validrange == true) + { + if (filesize > filestart) + { + data.Skip(filestart); + std::ostringstream contentlength; + contentlength << "Content-Length: " << (filesize - filestart); + headers.push_back(contentlength.str()); + std::ostringstream contentrange; + contentrange << "Content-Range: bytes " << filestart << "-" + << filesize - 1 << "/" << filesize; + headers.push_back(contentrange.str()); + sendHead(client, 206, headers); + if (sendContent == true) + sendFile(client, data); + continue; + } + else + { + headers.push_back("Content-Length: 0"); + std::ostringstream contentrange; + contentrange << "Content-Range: bytes */" << filesize; + headers.push_back(contentrange.str()); + sendHead(client, 416, headers); + continue; + } + } + } + } + addFileHeaders(headers, data); sendHead(client, 200, headers); if (sendContent == true) -- cgit v1.2.3-70-g09d2 From 93a99dac870584ed4ea78f1c2f262db8b5460962 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 11 Oct 2013 13:21:01 +0200 Subject: webserver: spurious newline after data confuses curl Webserver wrongly sends an additional newline after the data which causes curl to believe that the next request on this socket has no header data and so includes all headers in the data output. Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 4dae342dd..6c5634de6 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -137,21 +137,21 @@ bool sendFile(int const client, FileFd &data) /*{{{*/ { if (actual == 0) break; - if (Success == true) - Success &= FileFd::Write(client, buffer, actual); + Success &= FileFd::Write(client, buffer, actual); } - if (Success == true) - Success &= FileFd::Write(client, "\r\n", 2); + if (Success == false) + std::cerr << "SENDFILE: READ/WRITE ERROR to " << client << std::endl; return Success; } /*}}}*/ bool sendData(int const client, std::string const &data) /*{{{*/ { - bool Success = true; - Success &= FileFd::Write(client, data.c_str(), data.size()); - if (Success == true) - Success &= FileFd::Write(client, "\r\n", 2); - return Success; + if (FileFd::Write(client, data.c_str(), data.size()) == false) + { + std::cerr << "SENDDATA: WRITE ERROR to " << client << std::endl; + return false; + } + return true; } /*}}}*/ void sendError(int const client, int const httpcode, std::string const &request,/*{{{*/ -- cgit v1.2.3-70-g09d2 From eab3a9b2e233d7a142c0fa90bd1ed16a3c0e6cc6 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 16 Oct 2013 16:46:55 +0200 Subject: webserver: implement ~user access to ~user/public_html/ pretty much useless for the testcases, but handy to test the webserver itself in 'real world' environments Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 6c5634de6..4ea1794bb 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -198,7 +198,17 @@ void sendRedirect(int const client, int const httpcode, std::string const &uri,/ addDataHeaders(headers, response); std::string location("Location: "); if (strncmp(uri.c_str(), "http://", 7) != 0) - location.append("http://").append(LookupTag(request, "Host")).append("/").append(uri); + { + location.append("http://").append(LookupTag(request, "Host")).append("/"); + if (strncmp("/home/", uri.c_str(), strlen("/home/")) == 0 && uri.find("/public_html/") != std::string::npos) + { + std::string homeuri = SubstVar(uri, "/home/", "~"); + homeuri = SubstVar(homeuri, "/public_html/", "/"); + location.append(homeuri); + } + else + location.append(uri); + } else location.append(uri); headers.push_back(location); @@ -381,6 +391,20 @@ bool parseFirstLine(int const client, std::string const &request, /*{{{*/ filename.erase(0, 1); if (filename.empty() == true) filename = "."; + // support ~user/ uris to refer to /home/user/public_html/ as a kind-of special directory + else if (filename[0] == '~') + { + // /home/user is actually not entirely correct, but good enough for now + size_t dashpos = filename.find('/'); + if (dashpos != std::string::npos) + { + std::string home = filename.substr(1, filename.find('/') - 1); + std::string pubhtml = filename.substr(filename.find('/') + 1); + filename = "/home/" + home + "/public_html/" + pubhtml; + } + else + filename = "/home/" + filename.substr(1) + "/public_html/"; + } return true; } /*}}}*/ -- cgit v1.2.3-70-g09d2 From 3c16b5fe7950e32a0a13ad7544ed531ace535316 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 16 Oct 2013 18:43:21 +0200 Subject: webserver: add directoryIndex support defaulting to index.html Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 4ea1794bb..0e04826c5 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -277,7 +277,7 @@ void sendDirectoryListing(int const client, std::string const &dir, /*{{{*/ << "" << std::endl << "

Index of " << dir << "

" << std::endl << "" << std::endl; - if (dir != ".") + if (dir != "./") listing << ""; for (int i = 0; i < counter; ++i) { struct stat fs; @@ -390,7 +390,7 @@ bool parseFirstLine(int const client, std::string const &request, /*{{{*/ // nuke the first character which is a / as we assured above filename.erase(0, 1); if (filename.empty() == true) - filename = "."; + filename = "./"; // support ~user/ uris to refer to /home/user/public_html/ as a kind-of special directory else if (filename[0] == '~') { @@ -405,6 +405,17 @@ bool parseFirstLine(int const client, std::string const &request, /*{{{*/ else filename = "/home/" + filename.substr(1) + "/public_html/"; } + + // if no filename is given, but a valid directory see if we can use an index or + // have to resort to a autogenerated directory listing later on + if (DirectoryExists(filename) == true) + { + std::string const directoryIndex = _config->Find("aptwebserver::directoryindex"); + if (directoryIndex.empty() == false && directoryIndex == flNotDir(directoryIndex) && + RealFileExists(filename + directoryIndex) == true) + filename += directoryIndex; + } + return true; } /*}}}*/ @@ -543,6 +554,7 @@ int main(int const argc, const char * argv[]) _config->CndSet("aptwebserver::response-header::Server", "APT webserver"); _config->CndSet("aptwebserver::response-header::Accept-Ranges", "bytes"); + _config->CndSet("aptwebserver::directoryindex", "index.html"); std::vector messages; int client; @@ -693,7 +705,7 @@ int main(int const argc, const char * argv[]) } else if (DirectoryExists(filename) == true) { - if (filename == "." || filename[filename.length()-1] == '/') + if (filename[filename.length()-1] == '/') sendDirectoryListing(client, filename, *m, sendContent); else sendRedirect(client, 301, filename.append("/"), *m, sendContent); -- cgit v1.2.3-70-g09d2 From d23bda42456bd092751deb24d8295c27a15721e8 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 16 Oct 2013 22:43:01 +0200 Subject: webserver: strip parameters from filename Again, not (currently) used by the tests itself, but in interactive usage of the webserver itself. Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 0e04826c5..94f63bb39 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -308,7 +308,7 @@ void sendDirectoryListing(int const client, std::string const &dir, /*{{{*/ } /*}}}*/ bool parseFirstLine(int const client, std::string const &request, /*{{{*/ - std::string &filename, bool &sendContent, + std::string &filename, std::string ¶ms, bool &sendContent, bool &closeConnection) { if (strncmp(request.c_str(), "HEAD ", 5) == 0) @@ -375,6 +375,14 @@ bool parseFirstLine(int const client, std::string const &request, /*{{{*/ sendError(client, 400, request, sendContent, "Request is absolutePath, but configured to not accept that"); return false; } + + size_t paramspos = filename.find('?'); + if (paramspos != std::string::npos) + { + params = filename.substr(paramspos + 1); + filename.erase(paramspos); + } + filename = DeQuoteString(filename); // this is not a secure server, but at least prevent the obvious … -- cgit v1.2.3-70-g09d2 From 575fe03ee310c740bfa2950aa55b3358e8a60eee Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 16 Oct 2013 22:45:37 +0200 Subject: webserver: use pthreads to handle multiple clients Clients like browsers prefer to open many connections and keep them open for a while, so that pages with lot of subelements would take a while to load (if at all), by using threads as all servers do some way or another we can resolve this. libapt is not intended to be pthread-safe and stuff like the storage of the last return code doesn't make too much sense if multiple clients interact with us, but it is good enough for now and an other interesting (mis)use of libapt in general. Git-Dch: Ignore --- test/interactive-helper/aptwebserver.cc | 362 ++++++++++++++++++-------------- test/interactive-helper/makefile | 2 +- 2 files changed, 201 insertions(+), 163 deletions(-) (limited to 'test/interactive-helper') diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 94f63bb39..7d3589c9d 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -112,7 +112,7 @@ bool sendHead(int const client, int const httpcode, std::list &head date.append(TimeRFC1123(time(NULL))); headers.push_back(date); - std::clog << ">>> RESPONSE >>>" << std::endl; + std::clog << ">>> RESPONSE to " << client << " >>>" << std::endl; bool Success = true; for (std::list::const_iterator h = headers.begin(); Success == true && h != headers.end(); ++h) @@ -470,6 +470,173 @@ bool handleOnTheFlyReconfiguration(int const client, std::string const &request, return false; } /*}}}*/ +void * handleClient(void * voidclient) /*{{{*/ +{ + int client = *((int*)(voidclient)); + std::clog << "ACCEPT client " << client << std::endl; + std::vector messages; + while (ReadMessages(client, messages)) + { + bool closeConnection = false; + for (std::vector::const_iterator m = messages.begin(); + m != messages.end() && closeConnection == false; ++m) { + std::clog << ">>> REQUEST from " << client << " >>>" << std::endl << *m + << std::endl << "<<<<<<<<<<<<<<<<" << std::endl; + std::list headers; + std::string filename; + std::string params; + bool sendContent = true; + if (parseFirstLine(client, *m, filename, params, sendContent, closeConnection) == false) + continue; + + // special webserver command request + if (filename.length() > 1 && filename[0] == '_') + { + std::vector parts = VectorizeString(filename, '/'); + if (parts[0] == "_config") + { + handleOnTheFlyReconfiguration(client, *m, parts); + continue; + } + } + + // string replacements in the requested filename + ::Configuration::Item const *Replaces = _config->Tree("aptwebserver::redirect::replace"); + if (Replaces != NULL) + { + std::string redirect = "/" + filename; + for (::Configuration::Item *I = Replaces->Child; I != NULL; I = I->Next) + redirect = SubstVar(redirect, I->Tag, I->Value); + redirect.erase(0,1); + if (redirect != filename) + { + sendRedirect(client, 301, redirect, *m, sendContent); + continue; + } + } + + ::Configuration::Item const *Overwrite = _config->Tree("aptwebserver::overwrite"); + if (Overwrite != NULL) + { + for (::Configuration::Item *I = Overwrite->Child; I != NULL; I = I->Next) + { + regex_t *pattern = new regex_t; + int const res = regcomp(pattern, I->Tag.c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB); + if (res != 0) + { + char error[300]; + regerror(res, pattern, error, sizeof(error)); + sendError(client, 500, *m, sendContent, error); + continue; + } + if (regexec(pattern, filename.c_str(), 0, 0, 0) == 0) + { + filename = _config->Find("aptwebserver::overwrite::" + I->Tag + "::filename", filename); + if (filename[0] == '/') + filename.erase(0,1); + regfree(pattern); + break; + } + regfree(pattern); + } + } + + // deal with the request + if (RealFileExists(filename) == true) + { + FileFd data(filename, FileFd::ReadOnly); + std::string condition = LookupTag(*m, "If-Modified-Since", ""); + if (condition.empty() == false) + { + time_t cache; + if (RFC1123StrToTime(condition.c_str(), cache) == true && + cache >= data.ModificationTime()) + { + sendHead(client, 304, headers); + continue; + } + } + + if (_config->FindB("aptwebserver::support::range", true) == true) + condition = LookupTag(*m, "Range", ""); + else + condition.clear(); + if (condition.empty() == false && strncmp(condition.c_str(), "bytes=", 6) == 0) + { + time_t cache; + std::string ifrange; + if (_config->FindB("aptwebserver::support::if-range", true) == true) + ifrange = LookupTag(*m, "If-Range", ""); + bool validrange = (ifrange.empty() == true || + (RFC1123StrToTime(ifrange.c_str(), cache) == true && + cache <= data.ModificationTime())); + + // FIXME: support multiple byte-ranges (APT clients do not do this) + if (condition.find(',') == std::string::npos) + { + size_t start = 6; + unsigned long long filestart = strtoull(condition.c_str() + start, NULL, 10); + // FIXME: no support for last-byte-pos being not the end of the file (APT clients do not do this) + size_t dash = condition.find('-') + 1; + unsigned long long fileend = strtoull(condition.c_str() + dash, NULL, 10); + unsigned long long filesize = data.FileSize(); + if ((fileend == 0 || (fileend == filesize && fileend >= filestart)) && + validrange == true) + { + if (filesize > filestart) + { + data.Skip(filestart); + std::ostringstream contentlength; + contentlength << "Content-Length: " << (filesize - filestart); + headers.push_back(contentlength.str()); + std::ostringstream contentrange; + contentrange << "Content-Range: bytes " << filestart << "-" + << filesize - 1 << "/" << filesize; + headers.push_back(contentrange.str()); + sendHead(client, 206, headers); + if (sendContent == true) + sendFile(client, data); + continue; + } + else + { + headers.push_back("Content-Length: 0"); + std::ostringstream contentrange; + contentrange << "Content-Range: bytes */" << filesize; + headers.push_back(contentrange.str()); + sendHead(client, 416, headers); + continue; + } + } + } + } + + addFileHeaders(headers, data); + sendHead(client, 200, headers); + if (sendContent == true) + sendFile(client, data); + } + else if (DirectoryExists(filename) == true) + { + if (filename[filename.length()-1] == '/') + sendDirectoryListing(client, filename, *m, sendContent); + else + sendRedirect(client, 301, filename.append("/"), *m, sendContent); + } + else + sendError(client, 404, *m, sendContent); + } + _error->DumpErrors(std::cerr); + messages.clear(); + if (closeConnection == true) + break; + } + close(client); + std::clog << "CLOSE client " << client << std::endl; + return NULL; +} + /*}}}*/ + int main(int const argc, const char * argv[]) { CommandLine::Args Args[] = { @@ -490,6 +657,9 @@ int main(int const argc, const char * argv[]) // create socket, bind and listen to it {{{ // ignore SIGPIPE, this can happen on write() if the socket closes connection signal(SIGPIPE, SIG_IGN); + // we don't care for our slaves, so ignore their death + signal(SIGCHLD, SIG_IGN); + int sock = socket(AF_INET6, SOCK_STREAM, 0); if(sock < 0) { @@ -557,179 +727,47 @@ int main(int const argc, const char * argv[]) std::clog << "Serving ANY file on port: " << port << std::endl; - listen(sock, 1); + int const slaves = _config->FindB("aptwebserver::slaves", SOMAXCONN); + listen(sock, slaves); /*}}}*/ _config->CndSet("aptwebserver::response-header::Server", "APT webserver"); _config->CndSet("aptwebserver::response-header::Accept-Ranges", "bytes"); _config->CndSet("aptwebserver::directoryindex", "index.html"); - std::vector messages; - int client; - while ((client = accept(sock, NULL, NULL)) != -1) - { - std::clog << "ACCEPT client " << client - << " on socket " << sock << std::endl; + std::list accepted_clients; - while (ReadMessages(client, messages)) + while (true) + { + int client = accept(sock, NULL, NULL); + if (client == -1) { - bool closeConnection = false; - for (std::vector::const_iterator m = messages.begin(); - m != messages.end() && closeConnection == false; ++m) { - std::clog << ">>> REQUEST >>>>" << std::endl << *m - << std::endl << "<<<<<<<<<<<<<<<<" << std::endl; - std::list headers; - std::string filename; - bool sendContent = true; - if (parseFirstLine(client, *m, filename, sendContent, closeConnection) == false) - continue; - - // special webserver command request - if (filename.length() > 1 && filename[0] == '_') - { - std::vector parts = VectorizeString(filename, '/'); - if (parts[0] == "_config") - { - handleOnTheFlyReconfiguration(client, *m, parts); - continue; - } - } - - // string replacements in the requested filename - ::Configuration::Item const *Replaces = _config->Tree("aptwebserver::redirect::replace"); - if (Replaces != NULL) - { - std::string redirect = "/" + filename; - for (::Configuration::Item *I = Replaces->Child; I != NULL; I = I->Next) - redirect = SubstVar(redirect, I->Tag, I->Value); - redirect.erase(0,1); - if (redirect != filename) - { - sendRedirect(client, 301, redirect, *m, sendContent); - continue; - } - } - - ::Configuration::Item const *Overwrite = _config->Tree("aptwebserver::overwrite"); - if (Overwrite != NULL) - { - for (::Configuration::Item *I = Overwrite->Child; I != NULL; I = I->Next) - { - regex_t *pattern = new regex_t; - int const res = regcomp(pattern, I->Tag.c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB); - if (res != 0) - { - char error[300]; - regerror(res, pattern, error, sizeof(error)); - sendError(client, 500, *m, sendContent, error); - continue; - } - if (regexec(pattern, filename.c_str(), 0, 0, 0) == 0) - { - filename = _config->Find("aptwebserver::overwrite::" + I->Tag + "::filename", filename); - if (filename[0] == '/') - filename.erase(0,1); - regfree(pattern); - break; - } - regfree(pattern); - } - } - - // deal with the request - if (RealFileExists(filename) == true) - { - FileFd data(filename, FileFd::ReadOnly); - std::string condition = LookupTag(*m, "If-Modified-Since", ""); - if (condition.empty() == false) - { - time_t cache; - if (RFC1123StrToTime(condition.c_str(), cache) == true && - cache >= data.ModificationTime()) - { - sendHead(client, 304, headers); - continue; - } - } - - if (_config->FindB("aptwebserver::support::range", true) == true) - condition = LookupTag(*m, "Range", ""); - else - condition.clear(); - if (condition.empty() == false && strncmp(condition.c_str(), "bytes=", 6) == 0) - { - time_t cache; - std::string ifrange; - if (_config->FindB("aptwebserver::support::if-range", true) == true) - ifrange = LookupTag(*m, "If-Range", ""); - bool validrange = (ifrange.empty() == true || - (RFC1123StrToTime(ifrange.c_str(), cache) == true && - cache <= data.ModificationTime())); - - // FIXME: support multiple byte-ranges (APT clients do not do this) - if (condition.find(',') == std::string::npos) - { - size_t start = 6; - unsigned long long filestart = strtoull(condition.c_str() + start, NULL, 10); - // FIXME: no support for last-byte-pos being not the end of the file (APT clients do not do this) - size_t dash = condition.find('-') + 1; - unsigned long long fileend = strtoull(condition.c_str() + dash, NULL, 10); - unsigned long long filesize = data.FileSize(); - if ((fileend == 0 || (fileend == filesize && fileend >= filestart)) && - validrange == true) - { - if (filesize > filestart) - { - data.Skip(filestart); - std::ostringstream contentlength; - contentlength << "Content-Length: " << (filesize - filestart); - headers.push_back(contentlength.str()); - std::ostringstream contentrange; - contentrange << "Content-Range: bytes " << filestart << "-" - << filesize - 1 << "/" << filesize; - headers.push_back(contentrange.str()); - sendHead(client, 206, headers); - if (sendContent == true) - sendFile(client, data); - continue; - } - else - { - headers.push_back("Content-Length: 0"); - std::ostringstream contentrange; - contentrange << "Content-Range: bytes */" << filesize; - headers.push_back(contentrange.str()); - sendHead(client, 416, headers); - continue; - } - } - } - } + if (errno == EINTR) + continue; + _error->Errno("accept", "Couldn't accept client on socket %d", sock); + _error->DumpErrors(std::cerr); + return 6; + } - addFileHeaders(headers, data); - sendHead(client, 200, headers); - if (sendContent == true) - sendFile(client, data); - } - else if (DirectoryExists(filename) == true) - { - if (filename[filename.length()-1] == '/') - sendDirectoryListing(client, filename, *m, sendContent); - else - sendRedirect(client, 301, filename.append("/"), *m, sendContent); - } - else - sendError(client, 404, *m, sendContent); - } + pthread_attr_t attr; + if (pthread_attr_init(&attr) != 0 || pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) + { + _error->Errno("pthread_attr", "Couldn't set detach attribute for a fresh thread to handle client %d on socket %d", client, sock); _error->DumpErrors(std::cerr); - messages.clear(); - if (closeConnection == true) - break; + close(client); + continue; } - std::clog << "CLOSE client " << client - << " on socket " << sock << std::endl; - close(client); + pthread_t tid; + // thats rather dirty, but we need to store the client socket somewhere safe + accepted_clients.push_front(client); + if (pthread_create(&tid, &attr, &handleClient, &(*accepted_clients.begin())) != 0) + { + _error->Errno("pthread_create", "Couldn't create a fresh thread to handle client %d on socket %d", client, sock); + _error->DumpErrors(std::cerr); + close(client); + continue; + } } pidfile.Close(); diff --git a/test/interactive-helper/makefile b/test/interactive-helper/makefile index f43df97e3..8dc014b98 100644 --- a/test/interactive-helper/makefile +++ b/test/interactive-helper/makefile @@ -41,7 +41,7 @@ include $(PROGRAM_H) # Program for testing udevcdrom PROGRAM=aptwebserver -SLIBS = -lapt-pkg +SLIBS = -lapt-pkg -lpthread LIB_MAKES = apt-pkg/makefile SOURCE = aptwebserver.cc include $(PROGRAM_H) -- cgit v1.2.3-70-g09d2 From f2c0ec8bdb00b44de240190dae39fa255b6c85de Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 23 Oct 2013 16:32:48 +0200 Subject: tests: add a webserverconfig method to abstract config The URI to use to set a config option is a bit arcane to write/remember and checking if the setting was successful doubly so. Git-Dch: Ignore --- test/integration/framework | 16 ++++++++++++++++ test/integration/test-partial-file-support | 6 ++---- test/integration/test-releasefile-verification | 2 +- test/interactive-helper/aptwebserver.cc | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) (limited to 'test/interactive-helper') diff --git a/test/integration/framework b/test/integration/framework index 6a2a78c83..89b5bb0e4 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -792,6 +792,22 @@ signreleasefiles() { msgdone "info" } +webserverconfig() { + msgtest "Set webserver config option '${1}' to" "$2" + downloadfile "http://localhost:8080/_config/set/${1}/${2}" '/dev/null' >/dev/null + local DOWNLOG='download-testfile.log' + rm -f "$DOWNLOG" + local STATUS="$(mktemp)" + addtrap "rm $STATUS;" + downloadfile "http://localhost:8080/_config/find/aptwebserver::last-status-code" "$STATUS" > "$DOWNLOG" + if [ "$(cat "$STATUS")" = '200' ]; then + msgpass + else + cat >&2 "$DOWNLOG" + msgfail "Statuscode was $(cat "$STATUS")" + fi +} + rewritesourceslist() { local APTARCHIVE="file://$(readlink -f "${TMPWORKINGDIRECTORY}/aptarchive")" for LIST in $(find rootdir/etc/apt/sources.list.d/ -name 'apt-test-*.list'); do diff --git a/test/integration/test-partial-file-support b/test/integration/test-partial-file-support index b176cc15e..382789e68 100755 --- a/test/integration/test-partial-file-support +++ b/test/integration/test-partial-file-support @@ -66,8 +66,7 @@ TESTFILE='aptarchive/testfile' cp -a ${TESTDIR}/framework $TESTFILE testrun() { - downloadfile "$1/_config/set/aptwebserver::support::range/true" '/dev/null' >/dev/null - testwebserverlaststatuscode '200' + webserverconfig 'aptwebserver::support::range' 'true' copysource $TESTFILE 0 ./testfile testdownloadfile 'no data' "${1}/testfile" './testfile' '=' @@ -94,8 +93,7 @@ testrun() { testdownloadfile 'old data' "${1}/testfile" './testfile' '=' testwebserverlaststatuscode '200' - downloadfile "$1/_config/set/aptwebserver::support::range/false" '/dev/null' >/dev/null - testwebserverlaststatuscode '200' + webserverconfig 'aptwebserver::support::range' 'false' copysource $TESTFILE 20 ./testfile testdownloadfile 'no server support' "${1}/testfile" './testfile' '=' diff --git a/test/integration/test-releasefile-verification b/test/integration/test-releasefile-verification index 9d34a521a..e558b83e8 100755 --- a/test/integration/test-releasefile-verification +++ b/test/integration/test-releasefile-verification @@ -11,7 +11,7 @@ buildaptarchive setupflataptarchive changetowebserver -downloadfile "http://localhost:8080/_config/set/aptwebserver::support::range/false" '/dev/null' >/dev/null +webserverconfig 'aptwebserver::support::range' 'false' prepare() { local DATE="${2:-now}" diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 7d3589c9d..b7663a76a 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -546,7 +546,7 @@ void * handleClient(void * voidclient) /*{{{*/ { FileFd data(filename, FileFd::ReadOnly); std::string condition = LookupTag(*m, "If-Modified-Since", ""); - if (condition.empty() == false) + if (_config->FindB("aptwebserver::support::modified-since", true) == true && condition.empty() == false) { time_t cache; if (RFC1123StrToTime(condition.c_str(), cache) == true && -- cgit v1.2.3-70-g09d2 From 9ce3cfc9309c55cc01018c88c1ca82779fd74431 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 16 Jan 2014 22:19:49 +0100 Subject: correct some style/performance/warnings from cppcheck The most "visible" change is from utime to utimensat/futimens as the first one isn't part of POSIX anymore. Reported-By: cppcheck Git-Dch: Ignore --- apt-inst/dirstream.cc | 20 +++++++--------- apt-pkg/contrib/fileutl.cc | 2 +- apt-pkg/contrib/gpgv.cc | 5 ++-- apt-pkg/contrib/hashes.cc | 5 ++-- apt-pkg/contrib/hashsum.cc | 7 +++--- apt-pkg/deb/dpkgpm.cc | 9 +++---- apt-pkg/install-progress.cc | 2 +- apt-private/private-list.cc | 12 +++++----- apt-private/private-search.cc | 8 +++---- ftparchive/multicompress.cc | 10 ++++---- methods/connect.cc | 6 ++--- methods/copy.cc | 18 +++++++------- methods/ftp.cc | 49 +++++++++++++++++++++------------------ methods/gzip.cc | 26 +++++++++++---------- methods/http.cc | 4 +--- methods/https.cc | 10 ++++---- methods/https.h | 2 +- methods/mirror.cc | 8 +++---- methods/rsh.cc | 36 ++++++++++++++-------------- methods/server.cc | 25 ++++++++++---------- methods/server.h | 2 +- test/interactive-helper/rpmver.cc | 9 ++++--- 22 files changed, 133 insertions(+), 142 deletions(-) (limited to 'test/interactive-helper') diff --git a/apt-inst/dirstream.cc b/apt-inst/dirstream.cc index 65d1aa188..b62bdcae1 100644 --- a/apt-inst/dirstream.cc +++ b/apt-inst/dirstream.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include #include /*}}}*/ @@ -93,19 +92,18 @@ bool pkgDirStream::FinishedFile(Item &Itm,int Fd) { if (Fd < 0) return true; - - if (close(Fd) != 0) - return _error->Errno("close",_("Failed to close file %s"),Itm.Name); /* Set the modification times. The only way it can fail is if someone has futzed with our file, which is intolerable :> */ - struct utimbuf Time; - Time.actime = Itm.MTime; - Time.modtime = Itm.MTime; - if (utime(Itm.Name,&Time) != 0) - _error->Errno("utime",_("Failed to close file %s"),Itm.Name); - - return true; + struct timespec times[2]; + times[0].tv_sec = times[1].tv_sec = Itm.MTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + if (futimens(Fd, times) != 0) + _error->Errno("futimens", "Failed to set modification time for %s",Itm.Name); + + if (close(Fd) != 0) + return _error->Errno("close",_("Failed to close file %s"),Itm.Name); + return true; } /*}}}*/ // DirStream::Fail - Failed processing a file /*{{{*/ diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index efbf7aaf4..1c8acd513 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -319,7 +319,7 @@ bool CreateDirectory(string const &Parent, string const &Path) return false; // we are not going to create directories "into the blue" - if (Path.find(Parent, 0) != 0) + if (Path.compare(0, Parent.length(), Parent) != 0) return false; vector const dirs = VectorizeString(Path.substr(Parent.size()), '/'); diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc index 0a469dd7a..9de227062 100644 --- a/apt-pkg/contrib/gpgv.cc +++ b/apt-pkg/contrib/gpgv.cc @@ -260,8 +260,7 @@ bool SplitClearSignedFile(std::string const &InFile, FileFd * const ContentFile, char *buf = NULL; size_t buf_size = 0; - ssize_t line_len = 0; - while ((line_len = getline(&buf, &buf_size, in)) != -1) + while (getline(&buf, &buf_size, in) != -1) { _strrstrip(buf); if (found_message_start == false) @@ -355,7 +354,7 @@ bool OpenMaybeClearSignedFile(std::string const &ClearSignedFileName, FileFd &Me return _error->Error("Couldn't open temporary file to work with %s", ClearSignedFileName.c_str()); _error->PushToStack(); - bool const splitDone = SplitClearSignedFile(ClearSignedFileName.c_str(), &MessageFile, NULL, NULL); + bool const splitDone = SplitClearSignedFile(ClearSignedFileName, &MessageFile, NULL, NULL); bool const errorDone = _error->PendingError(); _error->MergeWithStack(); if (splitDone == false) diff --git a/apt-pkg/contrib/hashes.cc b/apt-pkg/contrib/hashes.cc index b4c768db9..890573d9c 100644 --- a/apt-pkg/contrib/hashes.cc +++ b/apt-pkg/contrib/hashes.cc @@ -129,13 +129,12 @@ bool Hashes::AddFD(int const Fd,unsigned long long Size, bool const addMD5, bool const addSHA1, bool const addSHA256, bool const addSHA512) { unsigned char Buf[64*64]; - ssize_t Res = 0; - int ToEOF = (Size == 0); + bool const ToEOF = (Size == 0); while (Size != 0 || ToEOF) { unsigned long long n = sizeof(Buf); if (!ToEOF) n = std::min(Size, n); - Res = read(Fd,Buf,n); + ssize_t const Res = read(Fd,Buf,n); if (Res < 0 || (!ToEOF && Res != (ssize_t) n)) // error, or short read return false; if (ToEOF && Res == 0) // EOF diff --git a/apt-pkg/contrib/hashsum.cc b/apt-pkg/contrib/hashsum.cc index 289e43aa4..d02177724 100644 --- a/apt-pkg/contrib/hashsum.cc +++ b/apt-pkg/contrib/hashsum.cc @@ -9,13 +9,12 @@ /* */ bool SummationImplementation::AddFD(int const Fd, unsigned long long Size) { unsigned char Buf[64 * 64]; - ssize_t Res = 0; - int ToEOF = (Size == 0); + bool const ToEOF = (Size == 0); while (Size != 0 || ToEOF) { unsigned long long n = sizeof(Buf); if (!ToEOF) n = std::min(Size, n); - Res = read(Fd, Buf, n); + ssize_t const Res = read(Fd, Buf, n); if (Res < 0 || (!ToEOF && Res != (ssize_t) n)) // error, or short read return false; if (ToEOF && Res == 0) // EOF @@ -27,7 +26,7 @@ bool SummationImplementation::AddFD(int const Fd, unsigned long long Size) { } bool SummationImplementation::AddFD(FileFd &Fd, unsigned long long Size) { unsigned char Buf[64 * 64]; - bool ToEOF = (Size == 0); + bool const ToEOF = (Size == 0); while (Size != 0 || ToEOF) { unsigned long long n = sizeof(Buf); diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 14ce133cf..1967d5d26 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -568,7 +568,6 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line) std::string prefix = APT::String::Strip(list[0]); std::string pkgname; std::string action; - ostringstream status; // "processing" has the form "processing: action: pkg or trigger" // with action = ["install", "configure", "remove", "purge", "disappear", @@ -1652,7 +1651,7 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) io_errors.push_back(string("failed in write on buffer copy for %s")); io_errors.push_back(string("short read on buffer copy for %s")); - for (vector::iterator I = io_errors.begin(); I != io_errors.end(); I++) + for (vector::iterator I = io_errors.begin(); I != io_errors.end(); ++I) { vector list = VectorizeString(dgettext("dpkg", (*I).c_str()), '%'); if (list.size() > 1) { @@ -1767,13 +1766,11 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) string histfile_name = _config->FindFile("Dir::Log::History"); if (!histfile_name.empty()) { - FILE *log = NULL; - char buf[1024]; - fprintf(report, "DpkgHistoryLog:\n"); - log = fopen(histfile_name.c_str(),"r"); + FILE* log = fopen(histfile_name.c_str(),"r"); if(log != NULL) { + char buf[1024]; while( fgets(buf, sizeof(buf), log) != NULL) fprintf(report, " %s", buf); fclose(log); diff --git a/apt-pkg/install-progress.cc b/apt-pkg/install-progress.cc index fe065da4f..a3a4cc0e1 100644 --- a/apt-pkg/install-progress.cc +++ b/apt-pkg/install-progress.cc @@ -242,7 +242,7 @@ PackageManagerFancy::~PackageManagerFancy() void PackageManagerFancy::staticSIGWINCH(int signum) { std::vector::const_iterator I; - for(I = instances.begin(); I != instances.end(); I++) + for(I = instances.begin(); I != instances.end(); ++I) (*I)->HandleSIGWINCH(signum); } diff --git a/apt-private/private-list.cc b/apt-private/private-list.cc index a02ebf02d..898ee7222 100644 --- a/apt-private/private-list.cc +++ b/apt-private/private-list.cc @@ -61,7 +61,7 @@ class PackageNameMatcher : public Matcher /*{{{*/ public: PackageNameMatcher(const char **patterns) { - for(int i=0; patterns[i] != NULL; i++) + for(int i=0; patterns[i] != NULL; ++i) { std::string pattern = patterns[i]; #ifdef PACKAGE_MATCHER_ABI_COMPAT @@ -79,12 +79,12 @@ class PackageNameMatcher : public Matcher /*{{{*/ } virtual ~PackageNameMatcher() { - for(J=filters.begin(); J != filters.end(); J++) + for(J=filters.begin(); J != filters.end(); ++J) delete *J; } virtual bool operator () (const pkgCache::PkgIterator &P) { - for(J=filters.begin(); J != filters.end(); J++) + for(J=filters.begin(); J != filters.end(); ++J) { APT::CacheFilter::PackageMatcher *cachefilter = *J; if((*cachefilter)(P)) @@ -104,7 +104,7 @@ void ListAllVersions(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ std::ostream &outs) { for (pkgCache::VerIterator Ver = P.VersionList(); - Ver.end() == false; Ver++) + Ver.end() == false; ++Ver) ListSingleVersion(CacheFile, records, Ver, outs); } /*}}}*/ @@ -142,7 +142,7 @@ bool List(CommandLine &Cmd) Cache->Head().PackageCount, _("Listing")); GetLocalitySortedVersionSet(CacheFile, bag, matcher, progress); - for (LocalitySortedVersionSet::iterator V = bag.begin(); V != bag.end(); V++) + for (LocalitySortedVersionSet::iterator V = bag.begin(); V != bag.end(); ++V) { std::stringstream outs; if(_config->FindB("APT::Cmd::All-Versions", false) == true) @@ -159,7 +159,7 @@ bool List(CommandLine &Cmd) // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) // output the sorted map - for (K = output_map.begin(); K != output_map.end(); K++) + for (K = output_map.begin(); K != output_map.end(); ++K) std::cout << (*K).second << std::endl; diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc index ff4140fa7..ade12353a 100644 --- a/apt-private/private-search.cc +++ b/apt-private/private-search.cc @@ -61,18 +61,18 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ progress.OverallProgress(50, 100, 50, _("Full Text Search")); progress.SubProgress(bag.size()); int Done = 0; - for ( ;V != bag.end(); V++) + for ( ;V != bag.end(); ++V) { if (Done%500 == 0) progress.Progress(Done); - Done++; + ++Done; int i; pkgCache::DescIterator Desc = V.TranslatedDescription(); pkgRecords::Parser &parser = records.Lookup(Desc.FileList()); bool all_found = true; - for(i=0; patterns[i] != NULL; i++) + for(i=0; patterns[i] != NULL; ++i) { // FIXME: use regexp instead of simple find() const char *pattern = patterns[i]; @@ -93,7 +93,7 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) // output the sorted map - for (K = output_map.begin(); K != output_map.end(); K++) + for (K = output_map.begin(); K != output_map.end(); ++K) std::cout << (*K).second << std::endl; return true; diff --git a/ftparchive/multicompress.cc b/ftparchive/multicompress.cc index 1fea589e2..265fb1a80 100644 --- a/ftparchive/multicompress.cc +++ b/ftparchive/multicompress.cc @@ -21,9 +21,9 @@ #include #include +#include #include #include -#include #include #include @@ -234,14 +234,12 @@ bool MultiCompress::Finalize(unsigned long long &OutSize) else { // Update the mtime if necessary - if (UpdateMTime > 0 && + if (UpdateMTime > 0 && (Now - St.st_mtime > (signed)UpdateMTime || St.st_mtime > Now)) { - struct utimbuf Buf; - Buf.actime = Buf.modtime = Now; - utime(I->Output.c_str(),&Buf); + utimensat(AT_FDCWD, I->Output.c_str(), NULL, AT_SYMLINK_NOFOLLOW); Changed = true; - } + } } // Force the file permissions diff --git a/methods/connect.cc b/methods/connect.cc index fc7a72ee9..d9c9a1dd4 100644 --- a/methods/connect.cc +++ b/methods/connect.cc @@ -142,9 +142,9 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, // Convert the port name/number char ServStr[300]; if (Port != 0) - snprintf(ServStr,sizeof(ServStr),"%u",Port); + snprintf(ServStr,sizeof(ServStr),"%i", Port); else - snprintf(ServStr,sizeof(ServStr),"%s",Service); + snprintf(ServStr,sizeof(ServStr),"%s", Service); /* We used a cached address record.. Yes this is against the spec but the way we have setup our rotating dns suggests that this is more @@ -190,7 +190,7 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, { if (DefPort != 0) { - snprintf(ServStr,sizeof(ServStr),"%u",DefPort); + snprintf(ServStr, sizeof(ServStr), "%i", DefPort); DefPort = 0; continue; } diff --git a/methods/copy.cc b/methods/copy.cc index e81d0022b..744cc2b51 100644 --- a/methods/copy.cc +++ b/methods/copy.cc @@ -18,7 +18,6 @@ #include #include -#include #include #include /*}}}*/ @@ -71,18 +70,19 @@ bool CopyMethod::Fetch(FetchItem *Itm) } From.Close(); - To.Close(); - + // Transfer the modification times - struct utimbuf TimeBuf; - TimeBuf.actime = Buf.st_atime; - TimeBuf.modtime = Buf.st_mtime; - if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0) + struct timespec times[2]; + times[0].tv_sec = Buf.st_atime; + times[1].tv_sec = Buf.st_mtime; + times[0].tv_nsec = times[1].tv_nsec = 0; + if (futimens(To.Fd(), times) != 0) { To.OpFail(); - return _error->Errno("utime",_("Failed to set modification time")); + return _error->Errno("futimens",_("Failed to set modification time")); } - + To.Close(); + Hashes Hash; FileFd Fd(Res.Filename, FileFd::ReadOnly); Hash.AddFD(Fd); diff --git a/methods/ftp.cc b/methods/ftp.cc index 979adca62..2d05364d5 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -953,14 +952,16 @@ void FtpMethod::SigTerm(int) { if (FailFd == -1) _exit(100); - close(FailFd); - + // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(FailFd, times); + + close(FailFd); + _exit(100); } /*}}}*/ @@ -1059,13 +1060,14 @@ bool FtpMethod::Fetch(FetchItem *Itm) if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing) == false) { Fd.Close(); - + // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(FailFd, times); + // If the file is missing we hard fail and delete the destfile // otherwise transient fail if (Missing == true) { @@ -1077,20 +1079,21 @@ bool FtpMethod::Fetch(FetchItem *Itm) } Res.Size = Fd.Size(); + + // Timestamp + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(Fd.Fd(), times); + FailFd = -1; } - + Res.LastModified = FailTime; Res.TakeHashes(Hash); - - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(Queue->DestFile.c_str(),&UBuf); - FailFd = -1; URIDone(Res); - + return true; } /*}}}*/ diff --git a/methods/gzip.cc b/methods/gzip.cc index 48c8e9892..f1edb353b 100644 --- a/methods/gzip.cc +++ b/methods/gzip.cc @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -94,32 +93,35 @@ bool GzipMethod::Fetch(FetchItem *Itm) } From.Close(); - To.Close(); - + if (Failed == true) return false; - + // Transfer the modification times struct stat Buf; if (stat(Path.c_str(),&Buf) != 0) return _error->Errno("stat",_("Failed to stat")); - struct utimbuf TimeBuf; - TimeBuf.actime = Buf.st_atime; - TimeBuf.modtime = Buf.st_mtime; - if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0) - return _error->Errno("utime",_("Failed to set modification time")); + struct timespec times[2]; + times[0].tv_sec = Buf.st_atime; + times[1].tv_sec = Buf.st_mtime; + times[0].tv_nsec = times[1].tv_nsec = 0; + if (futimens(To.Fd(), times) != 0) + { + To.OpFail(); + return _error->Errno("futimens",_("Failed to set modification time")); + } + Res.Size = To.FileSize(); + To.Close(); if (stat(Itm->DestFile.c_str(),&Buf) != 0) return _error->Errno("stat",_("Failed to stat")); - + // Return a Done response Res.LastModified = Buf.st_mtime; - Res.Size = Buf.st_size; Res.TakeHashes(Hash); URIDone(Res); - return true; } /*}}}*/ diff --git a/methods/http.cc b/methods/http.cc index b22b61efc..e1390afcb 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -97,8 +97,6 @@ void CircleBuf::Reset() is non-blocking.. */ bool CircleBuf::Read(int Fd) { - unsigned long long BwReadMax; - while (1) { // Woops, buffer is full @@ -106,7 +104,7 @@ bool CircleBuf::Read(int Fd) return true; // what's left to read in this tick - BwReadMax = CircleBuf::BwReadLimit/BW_HZ; + unsigned long long const BwReadMax = CircleBuf::BwReadLimit/BW_HZ; if(CircleBuf::BwReadLimit) { struct timeval now; diff --git a/methods/https.cc b/methods/https.cc index 2a562434b..e16e36339 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -405,10 +404,11 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_getinfo(curl, CURLINFO_FILETIME, &Res.LastModified); if (Res.LastModified != -1) { - struct utimbuf UBuf; - UBuf.actime = Res.LastModified; - UBuf.modtime = Res.LastModified; - utime(File->Name().c_str(),&UBuf); + struct timespec times[2]; + times[0].tv_sec = Res.LastModified; + times[1].tv_sec = Res.LastModified; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(File->Fd(), times); } else Res.LastModified = resultStat.st_mtime; diff --git a/methods/https.h b/methods/https.h index 8632d6d02..89a89d19c 100644 --- a/methods/https.h +++ b/methods/https.h @@ -65,7 +65,7 @@ class HttpsMethod : public pkgAcqMethod public: FileFd *File; - HttpsMethod() : pkgAcqMethod("1.2",Pipeline | SendConfig) + HttpsMethod() : pkgAcqMethod("1.2",Pipeline | SendConfig), File(NULL) { File = 0; curl = curl_easy_init(); diff --git a/methods/mirror.cc b/methods/mirror.cc index 854366318..83ef0d133 100644 --- a/methods/mirror.cc +++ b/methods/mirror.cc @@ -114,7 +114,7 @@ bool MirrorMethod::Clean(string Dir) for(I=list.begin(); I != list.end(); ++I) { string uri = (*I)->GetURI(); - if(uri.find("mirror://") != 0) + if(uri.compare(0, strlen("mirror://"), "mirror://") != 0) continue; string BaseUri = uri.substr(0,uri.size()-1); if (URItoFileName(BaseUri) == Dir->d_name) @@ -198,9 +198,9 @@ bool MirrorMethod::RandomizeMirrorFile(string mirror_file) // "stable" on the same machine. this is to avoid running into out-of-sync // issues (i.e. Release/Release.gpg different on each mirror) struct utsname buf; - int seed=1, i; + int seed=1; if(uname(&buf) == 0) { - for(i=0,seed=1; buf.nodename[i] != 0; i++) { + for(int i=0,seed=1; buf.nodename[i] != 0; ++i) { seed = seed * 31 + buf.nodename[i]; } } @@ -306,7 +306,7 @@ bool MirrorMethod::InitMirrors() if (s.size() == 0) continue; // ignore non http lines - if (s.find("http://") != 0) + if (s.compare(0, strlen("http://"), "http://") != 0) continue; AllMirrors.push_back(s); diff --git a/methods/rsh.cc b/methods/rsh.cc index d76dca6ef..a441220bf 100644 --- a/methods/rsh.cc +++ b/methods/rsh.cc @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -395,13 +394,14 @@ void RSHMethod::SigTerm(int sig) { if (FailFd == -1) _exit(100); - close(FailFd); - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); + // Transfer the modification times + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(FailFd, times); + close(FailFd); _exit(100); } @@ -488,10 +488,11 @@ bool RSHMethod::Fetch(FetchItem *Itm) Fd.Close(); // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(FailFd, times); // If the file is missing we hard fail otherwise transient fail if (Missing == true) @@ -501,18 +502,17 @@ bool RSHMethod::Fetch(FetchItem *Itm) } Res.Size = Fd.Size(); + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(Fd.Fd(), times); + FailFd = -1; } Res.LastModified = FailTime; Res.TakeHashes(Hash); - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(Queue->DestFile.c_str(),&UBuf); - FailFd = -1; - URIDone(Res); return true; diff --git a/methods/server.cc b/methods/server.cc index a2128441c..e12c23c07 100644 --- a/methods/server.cc +++ b/methods/server.cc @@ -17,9 +17,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -368,14 +368,14 @@ void ServerMethod::SigTerm(int) { if (FailFd == -1) _exit(100); + + struct timespec times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_nsec = times[1].tv_nsec = 0; + futimens(FailFd, times); close(FailFd); - - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + _exit(100); } /*}}}*/ @@ -539,11 +539,10 @@ int ServerMethod::Loop() File = 0; // Timestamp - struct utimbuf UBuf; - time(&UBuf.actime); - UBuf.actime = Server->Date; - UBuf.modtime = Server->Date; - utime(Queue->DestFile.c_str(),&UBuf); + struct timespec times[2]; + times[0].tv_sec = times[1].tv_sec = Server->Date; + times[0].tv_nsec = times[1].tv_nsec = 0; + utimensat(AT_FDCWD, Queue->DestFile.c_str(), times, AT_SYMLINK_NOFOLLOW); // Send status to APT if (Result == true) diff --git a/methods/server.h b/methods/server.h index 4dc6a1f2f..2b81e6173 100644 --- a/methods/server.h +++ b/methods/server.h @@ -137,7 +137,7 @@ class ServerMethod : public pkgAcqMethod virtual ServerState * CreateServerState(URI uri) = 0; virtual void RotateDNS() = 0; - ServerMethod(const char *Ver,unsigned long Flags = 0) : pkgAcqMethod(Ver, Flags), PipelineDepth(0), AllowRedirect(false), Debug(false) {}; + ServerMethod(const char *Ver,unsigned long Flags = 0) : pkgAcqMethod(Ver, Flags), Server(NULL), File(NULL), PipelineDepth(0), AllowRedirect(false), Debug(false) {}; virtual ~ServerMethod() {}; }; diff --git a/test/interactive-helper/rpmver.cc b/test/interactive-helper/rpmver.cc index 9fc807de8..15c96cbbe 100644 --- a/test/interactive-helper/rpmver.cc +++ b/test/interactive-helper/rpmver.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #define xisdigit(x) isdigit(x) @@ -12,10 +13,8 @@ using namespace std; int rpmvercmp(const char * a, const char * b) { - char oldch1, oldch2; char * str1, * str2; char * one, * two; - int rc; int isnum; /* easy comparison to see if versions are identical */ @@ -53,9 +52,9 @@ int rpmvercmp(const char * a, const char * b) /* save character at the end of the alpha or numeric segment */ /* so that they can be restored after the comparison */ - oldch1 = *str1; + char oldch1 = *str1; *str1 = '\0'; - oldch2 = *str2; + char oldch2 = *str2; *str2 = '\0'; /* take care of the case where the two version segments are */ @@ -81,7 +80,7 @@ int rpmvercmp(const char * a, const char * b) /* segments are alpha or if they are numeric. don't return */ /* if they are equal because there might be more segments to */ /* compare */ - rc = strcmp(one, two); + int rc = strcmp(one, two); if (rc) return rc; /* restore character that was replaced by null above */ -- cgit v1.2.3-70-g09d2 From f9b4f12d65b827612b29071f05d605bc05fa62bd Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 13 Feb 2014 23:38:28 +0100 Subject: report https download start only if we really get it Reporting it via progress means that e.g. a redirect will trigger it, too, so you get a Get & Hit while http only reports a Hit as it should be. --- methods/https.cc | 3 ++- test/integration/test-bug-602412-dequote-redirect | 33 ++++++++++++++--------- test/interactive-helper/aptwebserver.cc | 20 +++++++++++--- 3 files changed, 39 insertions(+), 17 deletions(-) (limited to 'test/interactive-helper') diff --git a/methods/https.cc b/methods/https.cc index 146b2bfb8..d97fddf9e 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -75,6 +75,8 @@ HttpsMethod::write_data(void *buffer, size_t size, size_t nmemb, void *userp) { HttpsMethod *me = (HttpsMethod *)userp; + if (me->Res.Size == 0) + me->URIStart(me->Res); if(me->File->Write(buffer, size*nmemb) != true) return false; @@ -88,7 +90,6 @@ HttpsMethod::progress_callback(void *clientp, double dltotal, double dlnow, HttpsMethod *me = (HttpsMethod *)clientp; if(dltotal > 0 && me->Res.Size == 0) { me->Res.Size = (unsigned long long)dltotal; - me->URIStart(me->Res); } return 0; } diff --git a/test/integration/test-bug-602412-dequote-redirect b/test/integration/test-bug-602412-dequote-redirect index bcebb57b8..6393f0c27 100755 --- a/test/integration/test-bug-602412-dequote-redirect +++ b/test/integration/test-bug-602412-dequote-redirect @@ -15,15 +15,24 @@ changetowebserver -o aptwebserver::redirect::replace::/pool/=/newpool/ \ mv aptarchive/pool aptarchive/newpool mv aptarchive/dists aptarchive/newdists -msgtest 'Test redirection works in' 'apt-get update' -testsuccess --nomsg aptget update - -# check that I-M-S header is kept in redirections -testequal 'Hit http://localhost:8080 unstable InRelease -Hit http://localhost:8080 unstable/main Sources -Hit http://localhost:8080 unstable/main amd64 Packages -Hit http://localhost:8080 unstable/main Translation-en -Reading package lists...' aptget update #-o debug::pkgacquire=1 -o debug::pkgacquire::worker=1 - -msgtest 'Test redirection works in' 'package download' -testsuccess --nomsg aptget install unrelated --download-only -y +testrun() { + msgtest 'Test redirection works in' 'apt-get update' + testsuccess --nomsg aptget update + + # check that I-M-S header is kept in redirections + testequal "Hit $1 unstable InRelease +Hit $1 unstable/main Sources +Hit $1 unstable/main amd64 Packages +Hit $1 unstable/main Translation-en +Reading package lists..." aptget update + + msgtest 'Test redirection works in' 'package download' + testsuccess --nomsg aptget install unrelated --download-only -y +} + +testrun 'http://localhost:8080' + +rm -rf rootdir/var/lib/apt/lists rootdir/var/cache/apt/archives +changetohttpswebserver + +testrun 'https://localhost:4433' diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index b7663a76a..992f802a6 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -197,9 +197,14 @@ void sendRedirect(int const client, int const httpcode, std::string const &uri,/ response.append(request).append(""); addDataHeaders(headers, response); std::string location("Location: "); - if (strncmp(uri.c_str(), "http://", 7) != 0) + if (strncmp(uri.c_str(), "http://", 7) != 0 && strncmp(uri.c_str(), "https://", 8) != 0) { - location.append("http://").append(LookupTag(request, "Host")).append("/"); + std::string const host = LookupTag(request, "Host"); + if (host.find(":4433") != std::string::npos) + location.append("https://"); + else + location.append("http://"); + location.append(host).append("/"); if (strncmp("/home/", uri.c_str(), strlen("/home/")) == 0 && uri.find("/public_html/") != std::string::npos) { std::string homeuri = SubstVar(uri, "/home/", "~"); @@ -507,7 +512,8 @@ void * handleClient(void * voidclient) /*{{{*/ std::string redirect = "/" + filename; for (::Configuration::Item *I = Replaces->Child; I != NULL; I = I->Next) redirect = SubstVar(redirect, I->Tag, I->Value); - redirect.erase(0,1); + if (redirect.empty() == false && redirect[0] == '/') + redirect.erase(0,1); if (redirect != filename) { sendRedirect(client, 301, redirect, *m, sendContent); @@ -542,7 +548,13 @@ void * handleClient(void * voidclient) /*{{{*/ } // deal with the request - if (RealFileExists(filename) == true) + if (_config->FindB("aptwebserver::support::http", true) == false && + LookupTag(*m, "Host").find(":4433") == std::string::npos) + { + sendError(client, 400, *m, sendContent, "HTTP disabled, all requests must be HTTPS"); + continue; + } + else if (RealFileExists(filename) == true) { FileFd data(filename, FileFd::ReadOnly); std::string condition = LookupTag(*m, "If-Modified-Since", ""); -- cgit v1.2.3-70-g09d2
#NameSizeLast-Modified
dParent Directory--