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(-) 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 + << "" << std::endl; + if (dir != ".") + listing << ""; + 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 << "" + << ""; + if (S_ISDIR(fs.st_mode)) + listing << ""; + else + listing << ""; + listing << "" << std::endl; + } + listing << "
#NameSizeLast-Modified
dParent Directory--
" << ((S_ISDIR(fs.st_mode)) ? 'd' : 'f') << "d_name << "\">" << namelist[i]->d_name << "-" << SizeToStr(fs.st_size) << "B" << TimeRFC1123(fs.st_mtime) << "
" << 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-70-g09d2