HttpHandler.h 5.2 KB

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