HttpHandler.cpp 9.1 KB

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