aptwebserver.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #include <apt-pkg/strutl.h>
  2. #include <apt-pkg/fileutl.h>
  3. #include <apt-pkg/error.h>
  4. #include <apt-pkg/cmndline.h>
  5. #include <apt-pkg/configuration.h>
  6. #include <apt-pkg/init.h>
  7. #include <vector>
  8. #include <string>
  9. #include <list>
  10. #include <sstream>
  11. #include <sys/socket.h>
  12. #include <sys/types.h>
  13. #include <netinet/in.h>
  14. #include <unistd.h>
  15. #include <errno.h>
  16. #include <time.h>
  17. #include <stdlib.h>
  18. char const * const httpcodeToStr(int httpcode) { /*{{{*/
  19. switch (httpcode) {
  20. // Informational 1xx
  21. case 100: return "100 Continue";
  22. case 101: return "101 Switching Protocols";
  23. // Successful 2xx
  24. case 200: return "200 OK";
  25. case 201: return "201 Created";
  26. case 202: return "202 Accepted";
  27. case 203: return "203 Non-Authoritative Information";
  28. case 204: return "204 No Content";
  29. case 205: return "205 Reset Content";
  30. case 206: return "206 Partial Conent";
  31. // Redirections 3xx
  32. case 300: return "300 Multiple Choices";
  33. case 301: return "301 Moved Permanently";
  34. case 302: return "302 Found";
  35. case 303: return "303 See Other";
  36. case 304: return "304 Not Modified";
  37. case 305: return "304 Use Proxy";
  38. case 307: return "307 Temporary Redirect";
  39. // Client errors 4xx
  40. case 400: return "400 Bad Request";
  41. case 401: return "401 Unauthorized";
  42. case 402: return "402 Payment Required";
  43. case 403: return "403 Forbidden";
  44. case 404: return "404 Not Found";
  45. case 405: return "405 Method Not Allowed";
  46. case 406: return "406 Not Acceptable";
  47. case 407: return "Proxy Authentication Required";
  48. case 408: return "Request Time-out";
  49. case 409: return "Conflict";
  50. case 410: return "Gone";
  51. case 411: return "Length Required";
  52. case 412: return "Precondition Failed";
  53. case 413: return "Request Entity Too Large";
  54. case 414: return "Request-URI Too Large";
  55. case 415: return "Unsupported Media Type";
  56. case 416: return "Requested range not satisfiable";
  57. case 417: return "Expectation Failed";
  58. // Server error 5xx
  59. case 500: return "Internal Server Error";
  60. case 501: return "Not Implemented";
  61. case 502: return "Bad Gateway";
  62. case 503: return "Service Unavailable";
  63. case 504: return "Gateway Time-out";
  64. case 505: return "HTTP Version not supported";
  65. }
  66. return NULL;
  67. } /*}}}*/
  68. void addFileHeaders(std::list<std::string> &headers, FileFd &data) { /*{{{*/
  69. std::ostringstream contentlength;
  70. contentlength << "Content-Length: " << data.FileSize();
  71. headers.push_back(contentlength.str());
  72. std::string lastmodified("Last-Modified: ");
  73. lastmodified.append(TimeRFC1123(data.ModificationTime()));
  74. headers.push_back(lastmodified);
  75. } /*}}}*/
  76. bool sendHead(int client, int httpcode, std::list<std::string> &headers) { /*{{{*/
  77. string response("HTTP/1.1 ");
  78. response.append(httpcodeToStr(httpcode));
  79. headers.push_front(response);
  80. headers.push_back("Server: APT webserver");
  81. std::string date("Date: ");
  82. date.append(TimeRFC1123(time(NULL)));
  83. headers.push_back(date);
  84. std::clog << ">>> RESPONSE >>>" << std::endl;
  85. bool Success = true;
  86. for (std::list<std::string>::const_iterator h = headers.begin();
  87. Success == true && h != headers.end(); ++h) {
  88. Success &= FileFd::Write(client, h->c_str(), h->size());
  89. Success &= FileFd::Write(client, "\r\n", 2);
  90. std::clog << *h << std::endl;
  91. }
  92. Success &= FileFd::Write(client, "\r\n", 2);
  93. std::clog << "<<<<<<<<<<<<<<<<" << std::endl;
  94. return Success;
  95. } /*}}}*/
  96. bool sendFile(int client, FileFd &data) { /*{{{*/
  97. bool Success = true;
  98. char buffer[500];
  99. unsigned long long actual = 0;
  100. while ((Success &= data.Read(buffer, sizeof(buffer), &actual)) == true) {
  101. if (actual == 0)
  102. break;
  103. Success &= FileFd::Write(client, buffer, actual);
  104. }
  105. Success &= FileFd::Write(client, "\r\n", 2);
  106. return Success;
  107. } /*}}}*/
  108. bool sendData(int client, std::string &data) { /*{{{*/
  109. bool Success = true;
  110. Success &= FileFd::Write(client, data.c_str(), data.size());
  111. Success &= FileFd::Write(client, "\r\n", 2);
  112. return Success;
  113. } /*}}}*/
  114. void sendError(int client, int httpcode, string request, bool content) { /*{{{*/
  115. std::list<std::string> headers;
  116. sendHead(client, httpcode, headers);
  117. if (content == false)
  118. return;
  119. string response("<html><head><title>");
  120. response.append(httpcodeToStr(httpcode)).append("</title></head>");
  121. response.append("<body><h1>").append(httpcodeToStr(httpcode)).append("</h1");
  122. response.append("This error is a result of the request: <pre>");
  123. response.append(request).append("</pre></body></html>");
  124. sendData(client, response);
  125. } /*}}}*/
  126. int main(int argc, const char *argv[])
  127. {
  128. CommandLine::Args Args[] = {
  129. {0, "simulate-paywall", "aptwebserver::Simulate-Paywall",
  130. CommandLine::Boolean},
  131. {0, "port", "aptwebserver::port", CommandLine::HasArg},
  132. {0,0,0,0}
  133. };
  134. CommandLine CmdL(Args, _config);
  135. if(pkgInitConfig(*_config) == false || CmdL.Parse(argc,argv) == false) {
  136. _error->DumpErrors();
  137. exit(1);
  138. }
  139. // create socket, bind and listen to it {{{
  140. int sock = socket(AF_INET6, SOCK_STREAM, 0);
  141. if(sock < 0 ) {
  142. _error->Errno("aptwerbserver", "Couldn't create socket");
  143. _error->DumpErrors(std::cerr);
  144. return 1;
  145. }
  146. // get the port
  147. int const port = _config->FindI("aptwebserver::port", 8080);
  148. bool const simulate_broken_server = _config->FindB("aptwebserver::Simulate-Paywall", false);
  149. // ensure that we accept all connections: v4 or v6
  150. int const iponly = 0;
  151. setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &iponly, sizeof(iponly));
  152. // to not linger to an address
  153. int const enable = 1;
  154. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
  155. struct sockaddr_in6 locAddr;
  156. memset(&locAddr, 0, sizeof(locAddr));
  157. locAddr.sin6_family = AF_INET6;
  158. locAddr.sin6_port = htons(port);
  159. locAddr.sin6_addr = in6addr_any;
  160. if (bind(sock, (struct sockaddr*) &locAddr, sizeof(locAddr)) < 0) {
  161. _error->Errno("aptwerbserver", "Couldn't bind");
  162. _error->DumpErrors(std::cerr);
  163. return 2;
  164. }
  165. if (simulate_broken_server) {
  166. std::clog << "Simulating a broken web server that return nonsense "
  167. "for all querries" << std::endl;
  168. } else {
  169. std::clog << "Serving ANY file on port: " << port << std::endl;
  170. }
  171. listen(sock, 1);
  172. std::vector<std::string> messages;
  173. int client;
  174. while ((client = accept(sock, NULL, NULL)) != -1) {
  175. std::clog << "ACCEPT client " << client
  176. << " on socket " << sock << std::endl;
  177. while (ReadMessages(client, messages)) {
  178. for (std::vector<std::string>::const_iterator m = messages.begin();
  179. m != messages.end(); ++m) {
  180. std::clog << ">>> REQUEST >>>>" << std::endl << *m
  181. << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
  182. std::list<std::string> headers;
  183. bool sendContent = true;
  184. if (strncmp(m->c_str(), "HEAD ", 5) == 0)
  185. sendContent = false;
  186. if (strncmp(m->c_str(), "GET ", 4) != 0)
  187. sendError(client, 501, *m, true);
  188. std::string host = LookupTag(*m, "Host", "");
  189. if (host.empty() == true) {
  190. // RFC 2616 §14.23 Host
  191. sendError(client, 400, *m, sendContent);
  192. continue;
  193. }
  194. size_t const filestart = m->find(' ', 5);
  195. string filename = m->substr(5, filestart - 5);
  196. if (simulate_broken_server == true) {
  197. sendHead(client, 200, headers);
  198. string data("ni ni ni");
  199. sendData(client, data);
  200. }
  201. else if (RealFileExists(filename) == false)
  202. sendError(client, 404, *m, sendContent);
  203. else {
  204. FileFd data(filename, FileFd::ReadOnly);
  205. std::string condition = LookupTag(*m, "If-Modified-Since", "");
  206. if (condition.empty() == false) {
  207. time_t cache;
  208. if (RFC1123StrToTime(condition.c_str(), cache) == true &&
  209. cache >= data.ModificationTime()) {
  210. sendError(client, 304, *m, false);
  211. continue;
  212. }
  213. }
  214. addFileHeaders(headers, data);
  215. sendHead(client, 200, headers);
  216. if (sendContent == true)
  217. sendFile(client, data);
  218. }
  219. }
  220. _error->DumpErrors(std::cerr);
  221. messages.clear();
  222. std::clog << "CLOSE client " << client
  223. << " on socket " << sock << std::endl;
  224. close(client);
  225. }
  226. }
  227. return 0;
  228. }