diff options
author | David Kalnischkies <kalnischkies@gmail.com> | 2012-07-10 20:03:00 +0200 |
---|---|---|
committer | David Kalnischkies <kalnischkies@gmail.com> | 2012-07-10 20:03:00 +0200 |
commit | d64053295c5544c62d7743c13bd415e42cf8f84d (patch) | |
tree | 7f9965008b06f02b30d8dc7cf78d2ed3b1d6e11f /test | |
parent | dc57a59b1e7a904ad7263245fa2b1d6a5a55655e (diff) |
implement directory listing in your webserver
Diffstat (limited to 'test')
-rw-r--r-- | test/interactive-helper/aptwebserver.cc | 95 |
1 files changed, 91 insertions, 4 deletions
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 <sys/socket.h> #include <sys/types.h> +#include <sys/stat.h> #include <netinet/in.h> #include <unistd.h> #include <errno.h> #include <time.h> #include <stdlib.h> +#include <dirent.h> 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<std::string> 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 << "<html><head><title>Index of " << dir << "</title>" + << "<style type=\"text/css\"><!-- td {padding: 0.02em 0.5em 0.02em 0.5em;}" + << "tr:nth-child(even){background-color:#dfdfdf;}" + << "h1, td:nth-child(3){text-align:center;}" + << "table {margin-left:auto;margin-right:auto;} --></style>" + << "</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 != ".") + 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; + std::string filename(dir); + filename.append("/").append(namelist[i]->d_name); + stat(filename.c_str(), &fs); + listing << "<tr><td>" << ((S_ISDIR(fs.st_mode)) ? 'd' : 'f') << "</td>" + << "<td><a href=\"" << namelist[i]->d_name << "\">" << namelist[i]->d_name << "</a></td>"; + if (S_ISDIR(fs.st_mode)) + listing << "<td>-</td>"; + else + listing << "<td>" << SizeToStr(fs.st_size) << "B</td>"; + listing << "<td>" << TimeRFC1123(fs.st_mtime) << "</td></tr>" << std::endl; + } + listing << "</table></body></html>" << 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(); |