HttpHandler.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #ifndef HTTP_HANDLER_H_
  2. #define HTTP_HANDLER_H_
  3. #include "HttpService.h"
  4. #include "HttpParser.h"
  5. #include "FileCache.h"
  6. #include "hloop.h"
  7. #define HTTP_KEEPALIVE_TIMEOUT 75 // s
  8. /*
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <title>404 Not Found</title>
  13. </head>
  14. <body>
  15. <center><h1>404 Not Found</h1></center>
  16. <hr>
  17. </body>
  18. </html>
  19. */
  20. static inline void make_http_status_page(http_status status_code, std::string& page) {
  21. char szCode[8];
  22. snprintf(szCode, sizeof(szCode), "%d ", status_code);
  23. const char* status_message = http_status_str(status_code);
  24. page += R"(<!DOCTYPE html>
  25. <html>
  26. <head>
  27. <title>)";
  28. page += szCode; page += status_message;
  29. page += R"(</title>
  30. </head>
  31. <body>
  32. <center><h1>)";
  33. page += szCode; page += status_message;
  34. page += R"(</h1></center>
  35. <hr>
  36. </body>
  37. </html>)";
  38. }
  39. static inline void on_keepalive_timeout(htimer_t* timer) {
  40. hio_t* io = (hio_t*)timer->userdata;
  41. hclose(io);
  42. }
  43. class HttpHandler {
  44. public:
  45. HttpService* service;
  46. FileCache* files;
  47. char srcip[64];
  48. int srcport;
  49. HttpParser parser;
  50. HttpRequest req;
  51. HttpResponse res;
  52. file_cache_t* fc;
  53. hio_t* io;
  54. htimer_t* keepalive_timer;
  55. HttpHandler() {
  56. service = NULL;
  57. files = NULL;
  58. io = NULL;
  59. keepalive_timer = NULL;
  60. init();
  61. }
  62. ~HttpHandler() {
  63. if (keepalive_timer) {
  64. htimer_del(keepalive_timer);
  65. keepalive_timer = NULL;
  66. }
  67. }
  68. void init() {
  69. parser.parser_request_init(&req);
  70. req.init();
  71. res.init();
  72. fc = NULL;
  73. }
  74. void keepalive() {
  75. if (keepalive_timer == NULL) {
  76. keepalive_timer = htimer_add(io->loop, on_keepalive_timeout, HTTP_KEEPALIVE_TIMEOUT*1000, 1);
  77. keepalive_timer->userdata = io;
  78. }
  79. else {
  80. htimer_reset(keepalive_timer);
  81. }
  82. }
  83. int handle_request() {
  84. // preprocessor -> api -> web -> postprocessor
  85. // preprocessor
  86. if (service->preprocessor) {
  87. if (service->preprocessor(&req, &res) == HANDLE_DONE) {
  88. return HANDLE_DONE;
  89. }
  90. }
  91. http_api_handler api = NULL;
  92. int ret = service->GetApi(req.url.c_str(), req.method, &api);
  93. if (api) {
  94. // api service
  95. if (api(&req, &res) == HANDLE_DONE) {
  96. return HANDLE_DONE;
  97. }
  98. }
  99. else if (ret == HTTP_STATUS_METHOD_NOT_ALLOWED) {
  100. // Method Not Allowed
  101. res.status_code = HTTP_STATUS_METHOD_NOT_ALLOWED;
  102. }
  103. else if (req.method == HTTP_GET) {
  104. // web service
  105. std::string filepath = service->document_root;
  106. filepath += req.url.c_str();
  107. if (strcmp(req.url.c_str(), "/") == 0) {
  108. filepath += service->home_page;
  109. }
  110. fc = files->Open(filepath.c_str());
  111. // Not Found
  112. if (fc == NULL) {
  113. res.status_code = HTTP_STATUS_NOT_FOUND;
  114. }
  115. else {
  116. // Not Modified
  117. auto iter = req.headers.find("if-not-match");
  118. if (iter != req.headers.end() &&
  119. strcmp(iter->second.c_str(), fc->etag) == 0) {
  120. res.status_code = HTTP_STATUS_NOT_MODIFIED;
  121. fc = NULL;
  122. }
  123. else {
  124. iter = req.headers.find("if-modified-since");
  125. if (iter != req.headers.end() &&
  126. strcmp(iter->second.c_str(), fc->last_modified) == 0) {
  127. res.status_code = HTTP_STATUS_NOT_MODIFIED;
  128. fc = NULL;
  129. }
  130. }
  131. }
  132. }
  133. else {
  134. // Not Implemented
  135. res.status_code = HTTP_STATUS_NOT_IMPLEMENTED;
  136. }
  137. // html page
  138. if (res.status_code >= 400 && res.body.size() == 0) {
  139. // error page
  140. if (service->error_page.size() != 0) {
  141. std::string filepath = service->document_root;
  142. filepath += '/';
  143. filepath += service->error_page;
  144. fc = files->Open(filepath.c_str());
  145. }
  146. // status page
  147. if (fc == NULL && res.body.size() == 0) {
  148. res.content_type = TEXT_HTML;
  149. make_http_status_page(res.status_code, res.body);
  150. }
  151. }
  152. // file
  153. if (fc) {
  154. if (fc->content_type && *fc->content_type != '\0') {
  155. res.headers["Content-Type"] = fc->content_type;
  156. }
  157. res.headers["Content-Length"] = std::to_string(fc->filebuf.len);
  158. res.headers["Last-Modified"] = fc->last_modified;
  159. res.headers["Etag"] = fc->etag;
  160. }
  161. // postprocessor
  162. if (service->postprocessor) {
  163. if (service->postprocessor(&req, &res) == HANDLE_DONE) {
  164. return HANDLE_DONE;
  165. }
  166. }
  167. return HANDLE_DONE;
  168. }
  169. };
  170. #endif // HTTP_HANDLER_H_