]> git.saurik.com Git - apt.git/blobdiff - test/interactive-helper/aptwebserver.cc
webserver: strip parameters from filename
[apt.git] / test / interactive-helper / aptwebserver.cc
index 7134b37bc21db071655147c33333ed76f25c4d87..94f63bb39e590d3427fab91eb0d5d0e2d87f79f7 100644 (file)
@@ -100,8 +100,13 @@ bool sendHead(int const client, int const httpcode, std::list<std::string> &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<std::string> addheaders = VectorizeString(buffer.str(), '\n');
+   for (std::vector<std::string>::const_iterator h = addheaders.begin(); h != addheaders.end(); ++h)
+      headers.push_back(*h);
 
    std::string date("Date: ");
    date.append(TimeRFC1123(time(NULL)));
@@ -132,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,/*{{{*/
@@ -193,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);
@@ -262,7 +277,7 @@ void sendDirectoryListing(int const client, std::string const &dir, /*{{{*/
           << "</head>" << std::endl
           << "<body><h1>Index of " << dir << "</h1>" << std::endl
           << "<table><tr><th>#</th><th>Name</th><th>Size</th><th>Last-Modified</th></tr>" << std::endl;
-   if (dir != ".")
+   if (dir != "./")
       listing << "<tr><td>d</td><td><a href=\"..\">Parent Directory</a></td><td>-</td><td>-</td></tr>";
    for (int i = 0; i < counter; ++i) {
       struct stat fs;
@@ -293,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 &params, bool &sendContent,
                    bool &closeConnection)
 {
    if (strncmp(request.c_str(), "HEAD ", 5) == 0)
@@ -360,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 …
@@ -375,7 +398,32 @@ 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] == '~')
+   {
+      // /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/";
+   }
+
+   // 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;
 }
                                                                        /*}}}*/
@@ -512,6 +560,10 @@ 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");
+   _config->CndSet("aptwebserver::directoryindex", "index.html");
+
    std::vector<std::string> messages;
    int client;
    while ((client = accept(sock, NULL, NULL)) != -1)
@@ -600,6 +652,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)
@@ -607,7 +713,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);