HttpHandler.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. fc = NULL;
  70. parser.parser_request_init(&req);
  71. }
  72. void reset() {
  73. init();
  74. req.reset();
  75. res.reset();
  76. }
  77. void keepalive() {
  78. if (keepalive_timer == NULL) {
  79. keepalive_timer = htimer_add(io->loop, on_keepalive_timeout, HTTP_KEEPALIVE_TIMEOUT*1000, 1);
  80. keepalive_timer->userdata = io;
  81. }
  82. else {
  83. htimer_reset(keepalive_timer);
  84. }
  85. }
  86. int handle_request() {
  87. // preprocessor -> api -> web -> postprocessor
  88. // preprocessor
  89. if (service->preprocessor) {
  90. if (service->preprocessor(&req, &res) == HANDLE_DONE) {
  91. return HANDLE_DONE;
  92. }
  93. }
  94. http_api_handler api = NULL;
  95. int ret = service->GetApi(req.url.c_str(), req.method, &api);
  96. if (api) {
  97. // api service
  98. if (api(&req, &res) == HANDLE_DONE) {
  99. return HANDLE_DONE;
  100. }
  101. }
  102. else if (ret == HTTP_STATUS_METHOD_NOT_ALLOWED) {
  103. // Method Not Allowed
  104. res.status_code = HTTP_STATUS_METHOD_NOT_ALLOWED;
  105. }
  106. else if (req.method == HTTP_GET) {
  107. // web service
  108. std::string filepath = service->document_root;
  109. filepath += req.url.c_str();
  110. if (strcmp(req.url.c_str(), "/") == 0) {
  111. filepath += service->home_page;
  112. }
  113. fc = files->Open(filepath.c_str());
  114. // Not Found
  115. if (fc == NULL) {
  116. res.status_code = HTTP_STATUS_NOT_FOUND;
  117. }
  118. else {
  119. // Not Modified
  120. auto iter = req.headers.find("if-not-match");
  121. if (iter != req.headers.end() &&
  122. strcmp(iter->second.c_str(), fc->etag) == 0) {
  123. res.status_code = HTTP_STATUS_NOT_MODIFIED;
  124. fc = NULL;
  125. }
  126. else {
  127. iter = req.headers.find("if-modified-since");
  128. if (iter != req.headers.end() &&
  129. strcmp(iter->second.c_str(), fc->last_modified) == 0) {
  130. res.status_code = HTTP_STATUS_NOT_MODIFIED;
  131. fc = NULL;
  132. }
  133. }
  134. }
  135. }
  136. else {
  137. // Not Implemented
  138. res.status_code = HTTP_STATUS_NOT_IMPLEMENTED;
  139. }
  140. // html page
  141. if (res.status_code >= 400 && res.body.size() == 0) {
  142. // error page
  143. if (service->error_page.size() != 0) {
  144. std::string filepath = service->document_root;
  145. filepath += '/';
  146. filepath += service->error_page;
  147. fc = files->Open(filepath.c_str());
  148. }
  149. // status page
  150. if (fc == NULL && res.body.size() == 0) {
  151. res.content_type = TEXT_HTML;
  152. make_http_status_page(res.status_code, res.body);
  153. }
  154. }
  155. // file
  156. if (fc) {
  157. if (fc->content_type && *fc->content_type != '\0') {
  158. res.headers["Content-Type"] = fc->content_type;
  159. }
  160. res.headers["Content-Length"] = std::to_string(fc->filebuf.len);
  161. res.headers["Last-Modified"] = fc->last_modified;
  162. res.headers["Etag"] = fc->etag;
  163. }
  164. // postprocessor
  165. if (service->postprocessor) {
  166. if (service->postprocessor(&req, &res) == HANDLE_DONE) {
  167. return HANDLE_DONE;
  168. }
  169. }
  170. return HANDLE_DONE;
  171. }
  172. };
  173. #endif // HTTP_HANDLER_H_