1
0

HttpHandler.cpp 7.7 KB

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