]> git.saurik.com Git - apt.git/commitdiff
add (partial) partial request support for the webserver
authorDavid Kalnischkies <kalnischkies@gmail.com>
Thu, 12 Jul 2012 10:04:36 +0000 (12:04 +0200)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Thu, 12 Jul 2012 10:04:36 +0000 (12:04 +0200)
test/interactive-helper/aptwebserver.cc

index 4ef9631b8145446c3357fde34f4f3e1df38859d9..ff60d64a34889e63909b7e756c3d2d2252c154c6 100644 (file)
@@ -35,7 +35,7 @@ char const * const httpcodeToStr(int const httpcode) {                        /*{{{*/
       case 203: return "203 Non-Authoritative Information";
       case 204: return "204 No Content";
       case 205: return "205 Reset Content";
-      case 206: return "206 Partial Conent";
+      case 206: return "206 Partial Content";
       // Redirections 3xx
       case 300: return "300 Multiple Choices";
       case 301: return "301 Moved Permanently";
@@ -113,6 +113,8 @@ bool sendHead(int const client, int const httpcode, std::list<std::string> &head
    date.append(TimeRFC1123(time(NULL)));
    headers.push_back(date);
 
+   headers.push_back("Accept-Ranges: bytes");
+
    std::clog << ">>> RESPONSE >>>" << std::endl;
    bool Success = true;
    for (std::list<std::string>::const_iterator h = headers.begin();
@@ -135,7 +137,8 @@ bool sendFile(int const client, FileFd &data) {                             /*{{{*/
    while ((Success &= data.Read(buffer, sizeof(buffer), &actual)) == true) {
       if (actual == 0)
         break;
-      Success &= FileFd::Write(client, buffer, actual);
+      if (Success == true)
+        Success &= FileFd::Write(client, buffer, actual);
    }
    if (Success == true)
       Success &= FileFd::Write(client, "\r\n", 2);
@@ -268,7 +271,7 @@ void sendDirectoryListing(int const client, std::string const &dir, std::string
       sendData(client, response);
 }
                                                                        /*}}}*/
-bool parseFirstLine(int const client, std::string const &request, std::string &filename, bool &sendContent) { /*{{{*/
+bool parseFirstLine(int const client, std::string const &request, std::string &filename, bool &sendContent, bool &closeConnection) { /*{{{*/
    if (strncmp(request.c_str(), "HEAD ", 5) == 0)
       sendContent = false;
    if (strncmp(request.c_str(), "GET ", 4) != 0)
@@ -289,8 +292,12 @@ bool parseFirstLine(int const client, std::string const &request, std::string &f
 
    size_t httpstart = fileend;
    for (; request[httpstart] == ' '; ++httpstart);
-   if (strncmp(request.c_str() + httpstart, "HTTP/1.1\r", 9) != 0) {
-      sendError(client, 500, request, sendContent, "Not an HTTP/1.1 request");
+   if (strncmp(request.c_str() + httpstart, "HTTP/1.1\r", 9) == 0)
+      closeConnection = strcasecmp(LookupTag(request, "Connection", "Keep-Alive").c_str(), "Keep-Alive") != 0;
+   else if (strncmp(request.c_str() + httpstart, "HTTP/1.0\r", 9) == 0)
+      closeConnection = strcasecmp(LookupTag(request, "Connection", "Keep-Alive").c_str(), "close") == 0;
+   else {
+      sendError(client, 500, request, sendContent, "Not an HTTP/1.{0,1} request");
       return false;
    }
 
@@ -384,15 +391,15 @@ int main(int const argc, const char * argv[])
                << " on socket " << sock << std::endl;
 
       while (ReadMessages(client, messages)) {
+        bool closeConnection = false;
         for (std::vector<std::string>::const_iterator m = messages.begin();
-             m != messages.end(); ++m) {
+             m != messages.end() && closeConnection == false; ++m) {
            std::clog << ">>> REQUEST >>>>" << std::endl << *m
                      << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
-
            std::list<std::string> headers;
            std::string filename;
            bool sendContent = true;
-           if (parseFirstLine(client, *m, filename, sendContent) == false)
+           if (parseFirstLine(client, *m, filename, sendContent, closeConnection) == false)
               continue;
 
            std::string host = LookupTag(*m, "Host", "");
@@ -419,6 +426,52 @@ int main(int const argc, const char * argv[])
                     continue;
                  }
               }
+              condition = LookupTag(*m, "If-Range", "");
+              bool ignoreRange = false;
+              if (condition.empty() == false) {
+                 time_t cache;
+                 if (RFC1123StrToTime(condition.c_str(), cache) == false ||
+                     cache < data.ModificationTime())
+                    ignoreRange = true;
+              }
+              condition = LookupTag(*m, "Range", "");
+              if (ignoreRange == false && condition.empty() == false &&
+                  strncmp(condition.c_str(), "bytes=", 6) == 0) {
+                 size_t end = condition.find(',');
+                 // FIXME: support multiple byte-ranges
+                 if (end == std::string::npos) {
+                    size_t start = 6;
+                    unsigned long long filestart = strtoull(condition.c_str() + start, NULL, 10);
+                    // FIXME: no fileend support
+                    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) {
+                       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 0-0/" << filesize;
+                          headers.push_back(contentrange.str());
+                          sendHead(client, 416, headers);
+                          continue;
+                       }
+                    }
+                 }
+              }
+
               addFileHeaders(headers, data);
               sendHead(client, 200, headers);
               if (sendContent == true)
@@ -448,6 +501,8 @@ int main(int const argc, const char * argv[])
         }
         _error->DumpErrors(std::cerr);
         messages.clear();
+        if (closeConnection == true)
+           break;
       }
 
       std::clog << "CLOSE client " << client