aptwebserver.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. void addDataHeaders(std::list<std::string> &headers, std::string &data) {/*{{{*/
  77. std::ostringstream contentlength;
  78. contentlength << "Content-Length: " << data.size();
  79. headers.push_back(contentlength.str());
  80. } /*}}}*/
  81. bool sendHead(int client, int httpcode, std::list<std::string> &headers) { /*{{{*/
  82. string response("HTTP/1.1 ");
  83. response.append(httpcodeToStr(httpcode));
  84. headers.push_front(response);
  85. headers.push_back("Server: APT webserver");
  86. std::string date("Date: ");
  87. date.append(TimeRFC1123(time(NULL)));
  88. headers.push_back(date);
  89. std::clog << ">>> RESPONSE >>>" << std::endl;
  90. bool Success = true;
  91. for (std::list<std::string>::const_iterator h = headers.begin();
  92. Success == true && h != headers.end(); ++h) {
  93. Success &= FileFd::Write(client, h->c_str(), h->size());
  94. Success &= FileFd::Write(client, "\r\n", 2);
  95. std::clog << *h << std::endl;
  96. }
  97. Success &= FileFd::Write(client, "\r\n", 2);
  98. std::clog << "<<<<<<<<<<<<<<<<" << std::endl;
  99. return Success;
  100. } /*}}}*/
  101. bool sendFile(int client, FileFd &data) { /*{{{*/
  102. bool Success = true;
  103. char buffer[500];
  104. unsigned long long actual = 0;
  105. while ((Success &= data.Read(buffer, sizeof(buffer), &actual)) == true) {
  106. if (actual == 0)
  107. break;
  108. Success &= FileFd::Write(client, buffer, actual);
  109. }
  110. Success &= FileFd::Write(client, "\r\n", 2);
  111. return Success;
  112. } /*}}}*/
  113. bool sendData(int client, std::string &data) { /*{{{*/
  114. bool Success = true;
  115. Success &= FileFd::Write(client, data.c_str(), data.size());
  116. Success &= FileFd::Write(client, "\r\n", 2);
  117. return Success;
  118. } /*}}}*/
  119. void sendError(int client, int httpcode, string request, bool content) { /*{{{*/
  120. std::list<std::string> headers;
  121. string response;
  122. if (content == true) {
  123. response.append("<html><head><title>");
  124. response.append(httpcodeToStr(httpcode)).append("</title></head>");
  125. response.append("<body><h1>").append(httpcodeToStr(httpcode)).append("</h1");
  126. response.append("This error is a result of the request: <pre>");
  127. response.append(request).append("</pre></body></html>");
  128. addDataHeaders(headers, response);
  129. }
  130. sendHead(client, httpcode, headers);
  131. sendData(client, response);
  132. } /*}}}*/
  133. int main(int argc, const char *argv[])
  134. {
  135. CommandLine::Args Args[] = {
  136. {0, "simulate-paywall", "aptwebserver::Simulate-Paywall",
  137. CommandLine::Boolean},
  138. {0, "port", "aptwebserver::port", CommandLine::HasArg},
  139. {0,0,0,0}
  140. };
  141. CommandLine CmdL(Args, _config);
  142. if(CmdL.Parse(argc,argv) == false) {
  143. _error->DumpErrors();
  144. exit(1);
  145. }
  146. // create socket, bind and listen to it {{{
  147. int sock = socket(AF_INET6, SOCK_STREAM, 0);
  148. if(sock < 0 ) {
  149. _error->Errno("aptwerbserver", "Couldn't create socket");
  150. _error->DumpErrors(std::cerr);
  151. return 1;
  152. }
  153. // get the port
  154. int const port = _config->FindI("aptwebserver::port", 8080);
  155. bool const simulate_broken_server = _config->FindB("aptwebserver::Simulate-Paywall", false);
  156. // ensure that we accept all connections: v4 or v6
  157. int const iponly = 0;
  158. setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &iponly, sizeof(iponly));
  159. // to not linger to an address
  160. int const enable = 1;
  161. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
  162. struct sockaddr_in6 locAddr;
  163. memset(&locAddr, 0, sizeof(locAddr));
  164. locAddr.sin6_family = AF_INET6;
  165. locAddr.sin6_port = htons(port);
  166. locAddr.sin6_addr = in6addr_any;
  167. if (bind(sock, (struct sockaddr*) &locAddr, sizeof(locAddr)) < 0) {
  168. _error->Errno("aptwerbserver", "Couldn't bind");
  169. _error->DumpErrors(std::cerr);
  170. return 2;
  171. }
  172. if (simulate_broken_server) {
  173. std::clog << "Simulating a broken web server that return nonsense "
  174. "for all querries" << std::endl;
  175. } else {
  176. std::clog << "Serving ANY file on port: " << port << std::endl;
  177. }
  178. listen(sock, 1);
  179. std::vector<std::string> messages;
  180. int client;
  181. while ((client = accept(sock, NULL, NULL)) != -1) {
  182. std::clog << "ACCEPT client " << client
  183. << " on socket " << sock << std::endl;
  184. while (ReadMessages(client, messages)) {
  185. for (std::vector<std::string>::const_iterator m = messages.begin();
  186. m != messages.end(); ++m) {
  187. std::clog << ">>> REQUEST >>>>" << std::endl << *m
  188. << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
  189. std::list<std::string> headers;
  190. bool sendContent = true;
  191. if (strncmp(m->c_str(), "HEAD ", 5) == 0)
  192. sendContent = false;
  193. if (strncmp(m->c_str(), "GET ", 4) != 0)
  194. sendError(client, 501, *m, true);
  195. std::string host = LookupTag(*m, "Host", "");
  196. if (host.empty() == true) {
  197. // RFC 2616 §14.23 Host
  198. sendError(client, 400, *m, sendContent);
  199. continue;
  200. }
  201. size_t const filestart = m->find(' ', 5);
  202. string filename = m->substr(5, filestart - 5);
  203. if (simulate_broken_server == true) {
  204. string data("ni ni ni\n");
  205. addDataHeaders(headers, data);
  206. sendHead(client, 200, headers);
  207. sendData(client, data);
  208. }
  209. else if (RealFileExists(filename) == false)
  210. sendError(client, 404, *m, sendContent);
  211. else {
  212. FileFd data(filename, FileFd::ReadOnly);
  213. std::string condition = LookupTag(*m, "If-Modified-Since", "");
  214. if (condition.empty() == false) {
  215. time_t cache;
  216. if (RFC1123StrToTime(condition.c_str(), cache) == true &&
  217. cache >= data.ModificationTime()) {
  218. sendError(client, 304, *m, false);
  219. continue;
  220. }
  221. }
  222. addFileHeaders(headers, data);
  223. sendHead(client, 200, headers);
  224. if (sendContent == true)
  225. sendFile(client, data);
  226. }
  227. }
  228. _error->DumpErrors(std::cerr);
  229. messages.clear();
  230. }
  231. std::clog << "CLOSE client " << client
  232. << " on socket " << sock << std::endl;
  233. close(client);
  234. }
  235. return 0;
  236. }