aptwebserver.cc 7.2 KB

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