1
0

HttpHandler.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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*)timer->userdata;
  11. hclose(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(io->loop, on_keepalive_timeout, HTTP_KEEPALIVE_TIMEOUT*1000, 1);
  50. keepalive_timer->userdata = 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. std::string filepath = service->document_root;
  79. filepath += req.url.c_str();
  80. if (strcmp(req.url.c_str(), "/") == 0) {
  81. filepath += service->home_page;
  82. }
  83. if (filepath.c_str()[filepath.size()-1] != '/' ||
  84. (service->index_of.size() != 0 &&
  85. req.url.size() >= service->index_of.size() &&
  86. strnicmp(req.url.c_str(), service->index_of.c_str(), service->index_of.size()) == 0)) {
  87. fc = files->Open(filepath.c_str(), (void*)req.url.c_str());
  88. }
  89. if (fc == NULL) {
  90. // Not Found
  91. res.status_code = HTTP_STATUS_NOT_FOUND;
  92. }
  93. else {
  94. // Not Modified
  95. auto iter = req.headers.find("if-not-match");
  96. if (iter != req.headers.end() &&
  97. strcmp(iter->second.c_str(), fc->etag) == 0) {
  98. res.status_code = HTTP_STATUS_NOT_MODIFIED;
  99. fc = NULL;
  100. }
  101. else {
  102. iter = req.headers.find("if-modified-since");
  103. if (iter != req.headers.end() &&
  104. strcmp(iter->second.c_str(), fc->last_modified) == 0) {
  105. res.status_code = HTTP_STATUS_NOT_MODIFIED;
  106. fc = NULL;
  107. }
  108. }
  109. }
  110. }
  111. else {
  112. // Not Implemented
  113. res.status_code = HTTP_STATUS_NOT_IMPLEMENTED;
  114. }
  115. // html page
  116. if (res.status_code >= 400 && res.body.size() == 0) {
  117. // error page
  118. if (service->error_page.size() != 0) {
  119. std::string filepath = service->document_root;
  120. filepath += '/';
  121. filepath += service->error_page;
  122. fc = files->Open(filepath.c_str(), NULL);
  123. }
  124. // status page
  125. if (fc == NULL && res.body.size() == 0) {
  126. res.content_type = TEXT_HTML;
  127. make_http_status_page(res.status_code, res.body);
  128. }
  129. }
  130. // file
  131. if (fc) {
  132. if (fc->content_type && *fc->content_type != '\0') {
  133. res.headers["Content-Type"] = fc->content_type;
  134. }
  135. res.headers["Content-Length"] = std::to_string(fc->filebuf.len);
  136. res.headers["Last-Modified"] = fc->last_modified;
  137. res.headers["Etag"] = fc->etag;
  138. }
  139. // postprocessor
  140. if (service->postprocessor) {
  141. if (service->postprocessor(&req, &res) == HANDLE_DONE) {
  142. return HANDLE_DONE;
  143. }
  144. }
  145. return HANDLE_DONE;
  146. }
  147. };
  148. #endif // HTTP_HANDLER_H_