From dc57a59b1e7a904ad7263245fa2b1d6a5a55655e Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Tue, 10 Jul 2012 18:00:11 +0200
Subject: reformat the aptwebserver code to look more like the rest of APT
---
test/interactive-helper/aptwebserver.cc | 89 ++++++++++++++++-----------------
1 file changed, 44 insertions(+), 45 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 8fbb9eab9..97a298c70 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -18,7 +18,7 @@
#include
#include
-char const * const httpcodeToStr(int httpcode) { /*{{{*/
+char const * const httpcodeToStr(int const httpcode) { /*{{{*/
switch (httpcode) {
// Informational 1xx
case 100: return "100 Continue";
@@ -67,9 +67,9 @@ char const * const httpcodeToStr(int httpcode) { /*{{{*/
case 505: return "HTTP Version not supported";
}
return NULL;
-} /*}}}*/
-
-void addFileHeaders(std::list &headers, FileFd &data) { /*{{{*/
+}
+ /*}}}*/
+void addFileHeaders(std::list &headers, FileFd &data) { /*{{{*/
std::ostringstream contentlength;
contentlength << "Content-Length: " << data.FileSize();
headers.push_back(contentlength.str());
@@ -77,15 +77,15 @@ void addFileHeaders(std::list &headers, FileFd &data) { /*{{{*/
std::string lastmodified("Last-Modified: ");
lastmodified.append(TimeRFC1123(data.ModificationTime()));
headers.push_back(lastmodified);
-} /*}}}*/
-
+}
+ /*}}}*/
void addDataHeaders(std::list &headers, std::string &data) {/*{{{*/
std::ostringstream contentlength;
contentlength << "Content-Length: " << data.size();
headers.push_back(contentlength.str());
-} /*}}}*/
-
-bool sendHead(int client, int httpcode, std::list &headers) { /*{{{*/
+}
+ /*}}}*/
+bool sendHead(int const client, int const httpcode, std::list &headers) { /*{{{*/
string response("HTTP/1.1 ");
response.append(httpcodeToStr(httpcode));
headers.push_front(response);
@@ -107,9 +107,9 @@ bool sendHead(int client, int httpcode, std::list &headers) { /*{{{
Success &= FileFd::Write(client, "\r\n", 2);
std::clog << "<<<<<<<<<<<<<<<<" << std::endl;
return Success;
-} /*}}}*/
-
-bool sendFile(int client, FileFd &data) { /*{{{*/
+}
+ /*}}}*/
+bool sendFile(int const client, FileFd &data) { /*{{{*/
bool Success = true;
char buffer[500];
unsigned long long actual = 0;
@@ -120,34 +120,32 @@ bool sendFile(int client, FileFd &data) { /*{{{*/
}
Success &= FileFd::Write(client, "\r\n", 2);
return Success;
-} /*}}}*/
-
-bool sendData(int client, std::string &data) { /*{{{*/
+}
+ /*}}}*/
+bool sendData(int const client, std::string const &data) { /*{{{*/
bool Success = true;
Success &= FileFd::Write(client, data.c_str(), data.size());
Success &= FileFd::Write(client, "\r\n", 2);
return Success;
-} /*}}}*/
-
-void sendError(int client, int httpcode, string request, bool content) { /*{{{*/
+}
+ /*}}}*/
+void sendError(int const client, int const httpcode, string const &request, bool content) { /*{{{*/
std::list headers;
- string response;
- if (content == true) {
- response.append("");
- response.append(httpcodeToStr(httpcode)).append("");
- response.append("").append(httpcodeToStr(httpcode)).append("
");
- response.append(request).append("");
- addDataHeaders(headers, response);
- }
+ string response("");
+ response.append(httpcodeToStr(httpcode)).append("");
+ response.append("").append(httpcodeToStr(httpcode)).append("
");
+ response.append(request).append("");
+ addDataHeaders(headers, response);
sendHead(client, httpcode, headers);
- sendData(client, response);
-} /*}}}*/
-
-int main(int argc, const char *argv[])
+ if (content == true)
+ sendData(client, response);
+}
+ /*}}}*/
+int main(int const argc, const char * argv[])
{
CommandLine::Args Args[] = {
- {0, "simulate-paywall", "aptwebserver::Simulate-Paywall",
+ {0, "simulate-paywall", "aptwebserver::Simulate-Paywall",
CommandLine::Boolean},
{0, "port", "aptwebserver::port", CommandLine::HasArg},
{0,0,0,0}
@@ -198,18 +196,19 @@ int main(int argc, const char *argv[])
}
listen(sock, 1);
+ /*}}}*/
std::vector messages;
int client;
while ((client = accept(sock, NULL, NULL)) != -1) {
std::clog << "ACCEPT client " << client
- << " on socket " << sock << std::endl;
+ << " on socket " << sock << std::endl;
while (ReadMessages(client, messages)) {
for (std::vector::const_iterator m = messages.begin();
m != messages.end(); ++m) {
- std::clog << ">>> REQUEST >>>>" << std::endl << *m
- << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
+ std::clog << ">>> REQUEST >>>>" << std::endl << *m
+ << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
std::list headers;
bool sendContent = true;
if (strncmp(m->c_str(), "HEAD ", 5) == 0)
@@ -227,12 +226,12 @@ int main(int argc, const char *argv[])
size_t const filestart = m->find(' ', 5);
string filename = m->substr(5, filestart - 5);
- if (simulate_broken_server == true) {
- string data("ni ni ni\n");
- addDataHeaders(headers, data);
- sendHead(client, 200, headers);
- sendData(client, data);
- }
+ if (simulate_broken_server == true) {
+ string data("ni ni ni\n");
+ addDataHeaders(headers, data);
+ sendHead(client, 200, headers);
+ sendData(client, data);
+ }
else if (RealFileExists(filename) == false)
sendError(client, 404, *m, sendContent);
else {
@@ -240,8 +239,8 @@ int main(int argc, const char *argv[])
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()) {
+ if (RFC1123StrToTime(condition.c_str(), cache) == true &&
+ cache >= data.ModificationTime()) {
sendError(client, 304, *m, false);
continue;
}
@@ -256,8 +255,8 @@ int main(int argc, const char *argv[])
messages.clear();
}
- std::clog << "CLOSE client " << client
- << " on socket " << sock << std::endl;
+ std::clog << "CLOSE client " << client
+ << " on socket " << sock << std::endl;
close(client);
}
return 0;
--
cgit v1.2.3
From d64053295c5544c62d7743c13bd415e42cf8f84d Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Tue, 10 Jul 2012 20:03:00 +0200
Subject: implement directory listing in your webserver
---
test/interactive-helper/aptwebserver.cc | 95 +++++++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 4 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 97a298c70..0b2720dad 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -12,11 +12,13 @@
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
char const * const httpcodeToStr(int const httpcode) { /*{{{*/
switch (httpcode) {
@@ -142,6 +144,86 @@ void sendError(int const client, int const httpcode, string const &request, bool
sendData(client, response);
}
/*}}}*/
+// sendDirectoryLisiting /*{{{*/
+int filter_hidden_files(const struct dirent *a) {
+ if (a->d_name[0] == '.')
+ return 0;
+#ifdef _DIRENT_HAVE_D_TYPE
+ // if we have the d_type check that only files and dirs will be included
+ if (a->d_type != DT_UNKNOWN &&
+ a->d_type != DT_REG &&
+ a->d_type != DT_LNK && // this includes links to regular files
+ a->d_type != DT_DIR)
+ return 0;
+#endif
+ return 1;
+}
+int grouped_alpha_case_sort(const struct dirent **a, const struct dirent **b) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if ((*a)->d_type == DT_DIR && (*b)->d_type == DT_DIR);
+ else if ((*a)->d_type == DT_DIR && (*b)->d_type == DT_REG)
+ return -1;
+ else if ((*b)->d_type == DT_DIR && (*a)->d_type == DT_REG)
+ return 1;
+ else
+#endif
+ {
+ struct stat f_prop; //File's property
+ stat((*a)->d_name, &f_prop);
+ int const amode = f_prop.st_mode;
+ stat((*b)->d_name, &f_prop);
+ int const bmode = f_prop.st_mode;
+ if (S_ISDIR(amode) && S_ISDIR(bmode));
+ else if (S_ISDIR(amode))
+ return -1;
+ else if (S_ISDIR(bmode))
+ return 1;
+ }
+ return strcasecmp((*a)->d_name, (*b)->d_name);
+}
+void sendDirectoryListing(int const client, string const &dir, string const &request, bool content) {
+ std::list headers;
+ std::ostringstream listing;
+
+ struct dirent **namelist;
+ int const counter = scandir(dir.c_str(), &namelist, filter_hidden_files, grouped_alpha_case_sort);
+ if (counter == -1) {
+ sendError(client, 500, request, content);
+ return;
+ }
+
+ listing << "Index of " << dir << ""
+ << ""
+ << "" << std::endl
+ << "Index of " << dir << "
" << std::endl
+ << "# | Name | Size | Last-Modified |
" << std::endl;
+ if (dir != ".")
+ listing << "d | Parent Directory | - | - |
";
+ for (int i = 0; i < counter; ++i) {
+ struct stat fs;
+ std::string filename(dir);
+ filename.append("/").append(namelist[i]->d_name);
+ stat(filename.c_str(), &fs);
+ listing << "" << ((S_ISDIR(fs.st_mode)) ? 'd' : 'f') << " | "
+ << "d_name << "\">" << namelist[i]->d_name << " | ";
+ if (S_ISDIR(fs.st_mode))
+ listing << "- | ";
+ else
+ listing << "" << SizeToStr(fs.st_size) << "B | ";
+ listing << "" << TimeRFC1123(fs.st_mtime) << " |
" << std::endl;
+ }
+ listing << "
" << std::endl;
+
+ std::string response(listing.str());
+ addDataHeaders(headers, response);
+ sendHead(client, 200, headers);
+ if (content == true)
+ sendData(client, response);
+}
+ /*}}}*/
int main(int const argc, const char * argv[])
{
CommandLine::Args Args[] = {
@@ -225,6 +307,8 @@ int main(int const argc, const char * argv[])
size_t const filestart = m->find(' ', 5);
string filename = m->substr(5, filestart - 5);
+ if (filename.empty() == true)
+ filename = ".";
if (simulate_broken_server == true) {
string data("ni ni ni\n");
@@ -232,16 +316,14 @@ int main(int const argc, const char * argv[])
sendHead(client, 200, headers);
sendData(client, data);
}
- else if (RealFileExists(filename) == false)
- sendError(client, 404, *m, sendContent);
- else {
+ else 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()) {
- sendError(client, 304, *m, false);
+ sendHead(client, 304, headers);
continue;
}
}
@@ -250,6 +332,11 @@ int main(int const argc, const char * argv[])
if (sendContent == true)
sendFile(client, data);
}
+ else if (DirectoryExists(filename) == true) {
+ sendDirectoryListing(client, filename, *m, sendContent);
+ }
+ else
+ sendError(client, 404, *m, false);
}
_error->DumpErrors(std::cerr);
messages.clear();
--
cgit v1.2.3
From 4958ba98e66af264e1f03f5dbacc713e51cd437d Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Tue, 10 Jul 2012 20:05:05 +0200
Subject: include our usual config.h in the webserver
---
test/interactive-helper/aptwebserver.cc | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 0b2720dad..0780288a4 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -1,3 +1,5 @@
+#include
+
#include
#include
#include
@@ -88,7 +90,7 @@ void addDataHeaders(std::list &headers, std::string &data) {/*{{{*/
}
/*}}}*/
bool sendHead(int const client, int const httpcode, std::list &headers) { /*{{{*/
- string response("HTTP/1.1 ");
+ std::string response("HTTP/1.1 ");
response.append(httpcodeToStr(httpcode));
headers.push_front(response);
@@ -131,9 +133,9 @@ bool sendData(int const client, std::string const &data) { /*{{{*/
return Success;
}
/*}}}*/
-void sendError(int const client, int const httpcode, string const &request, bool content) { /*{{{*/
+void sendError(int const client, int const httpcode, std::string const &request, bool content) { /*{{{*/
std::list headers;
- string response("");
+ std::string response("");
response.append(httpcodeToStr(httpcode)).append("");
response.append("").append(httpcodeToStr(httpcode)).append("
");
@@ -181,7 +183,7 @@ int grouped_alpha_case_sort(const struct dirent **a, const struct dirent **b) {
}
return strcasecmp((*a)->d_name, (*b)->d_name);
}
-void sendDirectoryListing(int const client, string const &dir, string const &request, bool content) {
+void sendDirectoryListing(int const client, std::string const &dir, std::string const &request, bool content) {
std::list headers;
std::ostringstream listing;
@@ -306,12 +308,12 @@ int main(int const argc, const char * argv[])
}
size_t const filestart = m->find(' ', 5);
- string filename = m->substr(5, filestart - 5);
+ std::string filename = m->substr(5, filestart - 5);
if (filename.empty() == true)
filename = ".";
if (simulate_broken_server == true) {
- string data("ni ni ni\n");
+ std::string data("ni ni ni\n");
addDataHeaders(headers, data);
sendHead(client, 200, headers);
sendData(client, data);
--
cgit v1.2.3
From 59fe94ea0135b1f8bc3d66e97460bd481054b061 Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Tue, 10 Jul 2012 20:08:58 +0200
Subject: http get requests need to be dequoted
---
test/interactive-helper/aptwebserver.cc | 2 ++
1 file changed, 2 insertions(+)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 0780288a4..920ab3bcc 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -311,6 +311,8 @@ int main(int const argc, const char * argv[])
std::string filename = m->substr(5, filestart - 5);
if (filename.empty() == true)
filename = ".";
+ else
+ filename = DeQuoteString(filename);
if (simulate_broken_server == true) {
std::string data("ni ni ni\n");
--
cgit v1.2.3
From 64a28515923aa67a1d109a82aba1892cd227bb15 Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Wed, 11 Jul 2012 00:46:27 +0200
Subject: ensure that directories are accessed with a slash at the end of the
url
---
test/interactive-helper/aptwebserver.cc | 40 +++++++++++++++++++++++++++------
1 file changed, 33 insertions(+), 7 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 920ab3bcc..2052fe6d8 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -146,6 +146,26 @@ void sendError(int const client, int const httpcode, std::string const &request,
sendData(client, response);
}
/*}}}*/
+void sendRedirect(int const client, int const httpcode, std::string const &uri, std::string const &request, bool content) { /*{{{*/
+ std::list headers;
+ std::string response("");
+ response.append(httpcodeToStr(httpcode)).append("");
+ response.append("").append(httpcodeToStr(httpcode)).append("
You should be redirected to ").append(uri).append("
");
+ response.append("This page is a result of the request: ");
+ response.append(request).append("
");
+ 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);
+ else
+ location.append(uri);
+ headers.push_back(location);
+ sendHead(client, httpcode, headers);
+ if (content == true)
+ sendData(client, response);
+}
+ /*}}}*/
// sendDirectoryLisiting /*{{{*/
int filter_hidden_files(const struct dirent *a) {
if (a->d_name[0] == '.')
@@ -209,12 +229,15 @@ void sendDirectoryListing(int const client, std::string const &dir, std::string
std::string filename(dir);
filename.append("/").append(namelist[i]->d_name);
stat(filename.c_str(), &fs);
- listing << "" << ((S_ISDIR(fs.st_mode)) ? 'd' : 'f') << " | "
- << "d_name << "\">" << namelist[i]->d_name << " | ";
- if (S_ISDIR(fs.st_mode))
- listing << "- | ";
- else
- listing << "" << SizeToStr(fs.st_size) << "B | ";
+ if (S_ISDIR(fs.st_mode)) {
+ listing << "
d | "
+ << "d_name << "/\">" << namelist[i]->d_name << " | "
+ << "- | ";
+ } else {
+ listing << "
f | "
+ << "d_name << "\">" << namelist[i]->d_name << " | "
+ << "" << SizeToStr(fs.st_size) << "B | ";
+ }
listing << "" << TimeRFC1123(fs.st_mtime) << " |
" << std::endl;
}
listing << "" << std::endl;
@@ -337,7 +360,10 @@ int main(int const argc, const char * argv[])
sendFile(client, data);
}
else if (DirectoryExists(filename) == true) {
- sendDirectoryListing(client, filename, *m, sendContent);
+ if (filename == "." || filename[filename.length()-1] == '/')
+ sendDirectoryListing(client, filename, *m, sendContent);
+ else
+ sendRedirect(client, 301, filename.append("/"), *m, sendContent);
}
else
sendError(client, 404, *m, false);
--
cgit v1.2.3
From d37911acee3eb34368e6d9e6a0046c9150d2bce6 Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Wed, 11 Jul 2012 11:07:54 +0200
Subject: add simple url rewriting to the webserver
---
test/interactive-helper/aptwebserver.cc | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 2052fe6d8..7fa322ea9 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -137,7 +137,7 @@ void sendError(int const client, int const httpcode, std::string const &request,
std::list headers;
std::string response("");
response.append(httpcodeToStr(httpcode)).append("");
- response.append("").append(httpcodeToStr(httpcode)).append("
").append(httpcodeToStr(httpcode)).append("
");
response.append("This error is a result of the request: ");
response.append(request).append("
");
addDataHeaders(headers, response);
@@ -255,6 +255,8 @@ int main(int const argc, const char * argv[])
{0, "simulate-paywall", "aptwebserver::Simulate-Paywall",
CommandLine::Boolean},
{0, "port", "aptwebserver::port", CommandLine::HasArg},
+ {'c',"config-file",0,CommandLine::ConfigFile},
+ {'o',"option",0,CommandLine::ArbItem},
{0,0,0,0}
};
@@ -366,7 +368,20 @@ int main(int const argc, const char * argv[])
sendRedirect(client, 301, filename.append("/"), *m, sendContent);
}
else
- sendError(client, 404, *m, false);
+ {
+ ::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;
+ }
+ }
+ sendError(client, 404, *m, sendContent);
+ }
}
_error->DumpErrors(std::cerr);
messages.clear();
--
cgit v1.2.3
From 7a1bed9d453379fcd22489bdb9f81f377abcaae2 Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Wed, 11 Jul 2012 17:11:26 +0200
Subject: rework parsing of the first request-line to be more robust
---
test/interactive-helper/aptwebserver.cc | 106 ++++++++++++++++++++++----------
1 file changed, 75 insertions(+), 31 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 7fa322ea9..4746aed96 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -51,24 +51,24 @@ char const * const httpcodeToStr(int const httpcode) { /*{{{*/
case 404: return "404 Not Found";
case 405: return "405 Method Not Allowed";
case 406: return "406 Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Time-out";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Request Entity Too Large";
- case 414: return "Request-URI Too Large";
- case 415: return "Unsupported Media Type";
- case 416: return "Requested range not satisfiable";
- case 417: return "Expectation Failed";
+ 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";
// Server error 5xx
- case 500: return "Internal Server Error";
- case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Time-out";
- case 505: return "HTTP Version not supported";
+ 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;
}
@@ -133,11 +133,13 @@ bool sendData(int const client, std::string const &data) { /*{{{*/
return Success;
}
/*}}}*/
-void sendError(int const client, int const httpcode, std::string const &request, bool content) { /*{{{*/
+void sendError(int const client, int const httpcode, std::string const &request, bool content, std::string const &error = "") { /*{{{*/
std::list headers;
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: ");
response.append(request).append("
");
addDataHeaders(headers, response);
@@ -249,6 +251,55 @@ 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) { /*{{{*/
+ if (strncmp(request.c_str(), "HEAD ", 5) == 0)
+ sendContent = false;
+ if (strncmp(request.c_str(), "GET ", 4) != 0)
+ {
+ sendError(client, 501, request, true);
+ return false;
+ }
+
+ size_t const lineend = request.find('\n');
+ size_t filestart = request.find(' ');
+ for (; request[filestart] == ' '; ++filestart);
+ size_t fileend = request.rfind(' ', lineend);
+ if (lineend == std::string::npos || filestart == std::string::npos ||
+ fileend == std::string::npos || filestart == fileend) {
+ sendError(client, 500, request, sendContent, "Filename can't be extracted");
+ return false;
+ }
+
+ 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");
+ return false;
+ }
+
+ filename = request.substr(filestart, fileend - filestart);
+ if (filename.find(' ') != std::string::npos) {
+ sendError(client, 500, request, sendContent, "Filename contains an unencoded space");
+ return false;
+ }
+ filename = DeQuoteString(filename);
+
+ // this is not a secure server, but at least prevent the obvious …
+ if (filename.empty() == true || filename[0] != '/' ||
+ strncmp(filename.c_str(), "//", 2) == 0 ||
+ filename.find_first_of("\r\n\t\f\v") != std::string::npos ||
+ filename.find("/../") != std::string::npos) {
+ sendError(client, 400, request, sendContent, "Filename contains illegal character (sequence)");
+ return false;
+ }
+
+ // nuke the first character which is a / as we assured above
+ filename.erase(0, 1);
+ if (filename.empty() == true)
+ filename = ".";
+ return true;
+}
+ /*}}}*/
int main(int const argc, const char * argv[])
{
CommandLine::Args Args[] = {
@@ -318,27 +369,20 @@ int main(int const argc, const char * argv[])
m != messages.end(); ++m) {
std::clog << ">>> REQUEST >>>>" << std::endl << *m
<< std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
+
std::list headers;
+ std::string filename;
bool sendContent = true;
- if (strncmp(m->c_str(), "HEAD ", 5) == 0)
- sendContent = false;
- if (strncmp(m->c_str(), "GET ", 4) != 0)
- sendError(client, 501, *m, true);
+ if (parseFirstLine(client, *m, filename, sendContent) == false)
+ continue;
std::string host = LookupTag(*m, "Host", "");
if (host.empty() == true) {
- // RFC 2616 §14.23 Host
- sendError(client, 400, *m, sendContent);
+ // RFC 2616 §14.23 requires Host
+ sendError(client, 400, *m, sendContent, "Host header is required");
continue;
}
- size_t const filestart = m->find(' ', 5);
- std::string filename = m->substr(5, filestart - 5);
- if (filename.empty() == true)
- filename = ".";
- else
- filename = DeQuoteString(filename);
-
if (simulate_broken_server == true) {
std::string data("ni ni ni\n");
addDataHeaders(headers, data);
--
cgit v1.2.3
From 57d13de2fb64a97d1a43d493c253ad2132ffd566 Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Wed, 11 Jul 2012 18:43:53 +0200
Subject: make the server a little more robust against write errors (e.g.
broken pipe)
---
test/interactive-helper/aptwebserver.cc | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 4746aed96..dbc4a19e0 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
char const * const httpcodeToStr(int const httpcode) { /*{{{*/
switch (httpcode) {
@@ -105,10 +106,12 @@ bool sendHead(int const client, int const httpcode, std::list &head
for (std::list::const_iterator h = headers.begin();
Success == true && h != headers.end(); ++h) {
Success &= FileFd::Write(client, h->c_str(), h->size());
- Success &= FileFd::Write(client, "\r\n", 2);
+ if (Success == true)
+ Success &= FileFd::Write(client, "\r\n", 2);
std::clog << *h << std::endl;
}
- Success &= FileFd::Write(client, "\r\n", 2);
+ if (Success == true)
+ Success &= FileFd::Write(client, "\r\n", 2);
std::clog << "<<<<<<<<<<<<<<<<" << std::endl;
return Success;
}
@@ -122,14 +125,16 @@ bool sendFile(int const client, FileFd &data) { /*{{{*/
break;
Success &= FileFd::Write(client, buffer, actual);
}
- Success &= FileFd::Write(client, "\r\n", 2);
+ if (Success == true)
+ Success &= FileFd::Write(client, "\r\n", 2);
return Success;
}
/*}}}*/
bool sendData(int const client, std::string const &data) { /*{{{*/
bool Success = true;
Success &= FileFd::Write(client, data.c_str(), data.size());
- Success &= FileFd::Write(client, "\r\n", 2);
+ if (Success == true)
+ Success &= FileFd::Write(client, "\r\n", 2);
return Success;
}
/*}}}*/
@@ -318,6 +323,8 @@ 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);
int sock = socket(AF_INET6, SOCK_STREAM, 0);
if(sock < 0 ) {
_error->Errno("aptwerbserver", "Couldn't create socket");
--
cgit v1.2.3
From 06b3095f81d9a730e8cb95274c8208cb0604cdfe Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Wed, 11 Jul 2012 19:11:24 +0200
Subject: add option to send Content-Type based on file extension
---
test/interactive-helper/aptwebserver.cc | 12 ++++++++++++
1 file changed, 12 insertions(+)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index dbc4a19e0..4ef9631b8 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -82,6 +82,18 @@ void addFileHeaders(std::list &headers, FileFd &data) { /*{{{*/
std::string lastmodified("Last-Modified: ");
lastmodified.append(TimeRFC1123(data.ModificationTime()));
headers.push_back(lastmodified);
+
+ std::string const fileext = flExtension(data.Name());
+ if (fileext.empty() == false && fileext != data.Name()) {
+ std::string confcontenttype("aptwebserver::ContentType::");
+ confcontenttype.append(fileext);
+ std::string const contenttype = _config->Find(confcontenttype);
+ if (contenttype.empty() == false) {
+ std::string header("Content-Type: ");
+ header.append(contenttype);
+ headers.push_back(header);
+ }
+ }
}
/*}}}*/
void addDataHeaders(std::list &headers, std::string &data) {/*{{{*/
--
cgit v1.2.3
From 056c36565706cad136df288db777c01555f4ecd9 Mon Sep 17 00:00:00 2001
From: David Kalnischkies
Date: Thu, 12 Jul 2012 12:04:36 +0200
Subject: add (partial) partial request support for the webserver
---
test/interactive-helper/aptwebserver.cc | 71 +++++++++++++++++++++++++++++----
1 file changed, 63 insertions(+), 8 deletions(-)
(limited to 'test/interactive-helper/aptwebserver.cc')
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index 4ef9631b8..ff60d64a3 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -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 &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::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::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 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
--
cgit v1.2.3