HttpHandler.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #include "HttpHandler.h"
  2. #include "hbase.h"
  3. #include "http_page.h"
  4. int HttpHandler::HandleHttpRequest() {
  5. // preprocessor -> api -> web -> postprocessor
  6. int ret = 0;
  7. http_api_handler api = NULL;
  8. req.ParseUrl();
  9. req.client_addr.ip = ip;
  10. req.client_addr.port = port;
  11. preprocessor:
  12. if (service->preprocessor) {
  13. ret = service->preprocessor(&req, &res);
  14. if (ret != 0) {
  15. goto make_http_status_page;
  16. }
  17. }
  18. if (service->api_handlers.size() != 0) {
  19. service->GetApi(&req, &api);
  20. }
  21. if (api) {
  22. // api service
  23. ret = api(&req, &res);
  24. if (ret != 0) {
  25. goto make_http_status_page;
  26. }
  27. }
  28. else if (service->document_root.size() != 0 &&
  29. (req.method == HTTP_GET || req.method == HTTP_HEAD)) {
  30. // web service
  31. // path safe check
  32. const char* req_path = req.path.c_str();
  33. if (*req_path != '/' || strstr(req_path, "/../")) {
  34. res.status_code = HTTP_STATUS_BAD_REQUEST;
  35. goto make_http_status_page;
  36. }
  37. std::string filepath = service->document_root;
  38. filepath += req_path;
  39. if (req_path[1] == '\0') {
  40. filepath += service->home_page;
  41. }
  42. bool is_dir = filepath.c_str()[filepath.size()-1] == '/';
  43. bool is_index_of = false;
  44. if (service->index_of.size() != 0 && strstartswith(req_path, service->index_of.c_str())) {
  45. is_index_of = true;
  46. }
  47. if (!is_dir || is_index_of) {
  48. bool need_read = req.method == HTTP_HEAD ? false : true;
  49. fc = files->Open(filepath.c_str(), need_read, (void*)req_path);
  50. }
  51. if (fc == NULL) {
  52. // Not Found
  53. ret = HTTP_STATUS_NOT_FOUND;
  54. }
  55. else {
  56. // Not Modified
  57. auto iter = req.headers.find("if-not-match");
  58. if (iter != req.headers.end() &&
  59. strcmp(iter->second.c_str(), fc->etag) == 0) {
  60. ret = HTTP_STATUS_NOT_MODIFIED;
  61. fc = NULL;
  62. }
  63. else {
  64. iter = req.headers.find("if-modified-since");
  65. if (iter != req.headers.end() &&
  66. strcmp(iter->second.c_str(), fc->last_modified) == 0) {
  67. ret = HTTP_STATUS_NOT_MODIFIED;
  68. fc = NULL;
  69. }
  70. }
  71. }
  72. }
  73. else {
  74. // Not Implemented
  75. ret = HTTP_STATUS_NOT_IMPLEMENTED;
  76. }
  77. make_http_status_page:
  78. if (ret >= 100 && ret < 600) {
  79. res.status_code = (http_status)ret;
  80. }
  81. if (res.status_code >= 400 && res.body.size() == 0 && req.method != HTTP_HEAD) {
  82. // error page
  83. if (service->error_page.size() != 0) {
  84. std::string filepath = service->document_root;
  85. filepath += '/';
  86. filepath += service->error_page;
  87. fc = files->Open(filepath.c_str(), true, NULL);
  88. }
  89. // status page
  90. if (fc == NULL && res.body.size() == 0) {
  91. res.content_type = TEXT_HTML;
  92. make_http_status_page(res.status_code, res.body);
  93. }
  94. }
  95. if (fc) {
  96. res.content = fc->filebuf.base;
  97. res.content_length = fc->filebuf.len;
  98. if (fc->content_type && *fc->content_type != '\0') {
  99. res.headers["Content-Type"] = fc->content_type;
  100. }
  101. res.headers["Last-Modified"] = fc->last_modified;
  102. res.headers["Etag"] = fc->etag;
  103. }
  104. postprocessor:
  105. if (service->postprocessor) {
  106. ret = service->postprocessor(&req, &res);
  107. }
  108. state = WANT_SEND;
  109. return ret;
  110. }
  111. int HttpHandler::GetSendData(char** data, size_t* len) {
  112. if (protocol == HTTP_V1) {
  113. switch(state) {
  114. case WANT_RECV:
  115. if (parser->IsComplete()) state = WANT_SEND;
  116. else return 0;
  117. case WANT_SEND:
  118. state = SEND_HEADER;
  119. case SEND_HEADER:
  120. {
  121. int content_length = 0;
  122. const char* content = NULL;
  123. // HEAD
  124. if (req.method == HTTP_HEAD) {
  125. if (fc) {
  126. res.headers["Accept-Ranges"] = "bytes";
  127. res.headers["Content-Length"] = hv::to_string(fc->st.st_size);
  128. } else {
  129. res.headers["Content-Type"] = "text/html";
  130. res.headers["Content-Length"] = "0";
  131. }
  132. state = SEND_DONE;
  133. goto return_nobody;
  134. }
  135. // File service
  136. if (fc) {
  137. long from, to, total;
  138. int nread;
  139. // Range:
  140. if (req.GetRange(from, to)) {
  141. HFile file;
  142. if (file.open(fc->filepath.c_str(), "rb") != 0) {
  143. res.status_code = HTTP_STATUS_NOT_FOUND;
  144. state = SEND_DONE;
  145. goto return_nobody;
  146. }
  147. total = file.size();
  148. if (to == 0 || to >= total) to = total - 1;
  149. res.content_length = to - from + 1;
  150. nread = file.readrange(body, from, to);
  151. if (nread != res.content_length) {
  152. res.status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
  153. state = SEND_DONE;
  154. goto return_nobody;
  155. }
  156. res.SetRange(from, to, total);
  157. state = SEND_BODY;
  158. goto return_header;
  159. }
  160. // FileCache
  161. // NOTE: no copy filebuf, more efficient
  162. header = res.Dump(true, false);
  163. fc->prepend_header(header.c_str(), header.size());
  164. *data = fc->httpbuf.base;
  165. *len = fc->httpbuf.len;
  166. state = SEND_DONE;
  167. return *len;
  168. }
  169. // API service
  170. content_length = res.ContentLength();
  171. content = (const char*)res.Content();
  172. if (content) {
  173. if (content_length > (1 << 20)) {
  174. state = SEND_BODY;
  175. goto return_header;
  176. } else {
  177. // NOTE: header+body in one package if <= 1M
  178. header = res.Dump(true, false);
  179. header.append(content, content_length);
  180. state = SEND_DONE;
  181. goto return_header;
  182. }
  183. } else {
  184. state = SEND_DONE;
  185. goto return_header;
  186. }
  187. return_nobody:
  188. res.content_length = 0;
  189. return_header:
  190. if (header.empty()) header = res.Dump(true, false);
  191. *data = (char*)header.c_str();
  192. *len = header.size();
  193. return *len;
  194. }
  195. case SEND_BODY:
  196. {
  197. if (body.empty()) {
  198. *data = (char*)res.Content();
  199. *len = res.ContentLength();
  200. } else {
  201. *data = (char*)body.c_str();
  202. *len = body.size();
  203. }
  204. state = SEND_DONE;
  205. return *len;
  206. }
  207. case SEND_DONE:
  208. {
  209. // NOTE: remove file cache if > 16M
  210. if (fc && fc->filebuf.len > (1 << 24)) {
  211. files->Close(fc);
  212. }
  213. fc = NULL;
  214. header.clear();
  215. body.clear();
  216. return 0;
  217. }
  218. default:
  219. return 0;
  220. }
  221. } else if (protocol == HTTP_V2) {
  222. return parser->GetSendData(data, len);
  223. }
  224. return 0;
  225. }