HttpHandler.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include "HttpHandler.h"
  2. #include "hbase.h"
  3. #include "herr.h"
  4. #include "hlog.h"
  5. #include "hasync.h" // import hv::async for http_async_handler
  6. #include "http_page.h"
  7. int HttpHandler::customHttpHandler(const http_handler& handler) {
  8. return invokeHttpHandler(&handler);
  9. }
  10. int HttpHandler::invokeHttpHandler(const http_handler* handler) {
  11. int status_code = HTTP_STATUS_NOT_IMPLEMENTED;
  12. if (handler->sync_handler) {
  13. // NOTE: sync_handler run on IO thread
  14. status_code = handler->sync_handler(req.get(), resp.get());
  15. } else if (handler->async_handler) {
  16. // NOTE: async_handler run on hv::async threadpool
  17. hv::async(std::bind(handler->async_handler, req, writer));
  18. status_code = HTTP_STATUS_UNFINISHED;
  19. } else if (handler->ctx_handler) {
  20. HttpContextPtr ctx(new hv::HttpContext);
  21. ctx->service = service;
  22. ctx->request = req;
  23. ctx->response = resp;
  24. ctx->writer = writer;
  25. // NOTE: ctx_handler run on IO thread, you can easily post HttpContextPtr to your consumer thread for processing.
  26. status_code = handler->ctx_handler(ctx);
  27. if (writer && writer->state != hv::HttpResponseWriter::SEND_BEGIN) {
  28. status_code = HTTP_STATUS_UNFINISHED;
  29. }
  30. }
  31. return status_code;
  32. }
  33. int HttpHandler::HandleHttpRequest() {
  34. // preprocessor -> processor -> postprocessor
  35. int status_code = HTTP_STATUS_OK;
  36. HttpRequest* pReq = req.get();
  37. HttpResponse* pResp = resp.get();
  38. pReq->scheme = ssl ? "https" : "http";
  39. pReq->client_addr.ip = ip;
  40. pReq->client_addr.port = port;
  41. pReq->Host();
  42. pReq->ParseUrl();
  43. // NOTE: Not all users want to parse body, we comment it out.
  44. // pReq->ParseBody();
  45. preprocessor:
  46. state = HANDLE_BEGIN;
  47. if (service->preprocessor) {
  48. status_code = customHttpHandler(service->preprocessor);
  49. if (status_code != 0) {
  50. goto postprocessor;
  51. }
  52. }
  53. processor:
  54. if (service->processor) {
  55. status_code = customHttpHandler(service->processor);
  56. } else {
  57. status_code = defaultRequestHandler();
  58. }
  59. postprocessor:
  60. if (status_code >= 100 && status_code < 600) {
  61. pResp->status_code = (http_status)status_code;
  62. }
  63. if (pResp->status_code >= 400 && pResp->body.size() == 0 && pReq->method != HTTP_HEAD) {
  64. if (service->errorHandler) {
  65. customHttpHandler(service->errorHandler);
  66. } else {
  67. defaultErrorHandler();
  68. }
  69. }
  70. if (fc) {
  71. pResp->content = fc->filebuf.base;
  72. pResp->content_length = fc->filebuf.len;
  73. pResp->headers["Content-Type"] = fc->content_type;
  74. pResp->headers["Last-Modified"] = fc->last_modified;
  75. pResp->headers["Etag"] = fc->etag;
  76. }
  77. if (service->postprocessor) {
  78. customHttpHandler(service->postprocessor);
  79. }
  80. if (status_code == 0) {
  81. state = HANDLE_CONTINUE;
  82. } else {
  83. state = HANDLE_END;
  84. parser->SubmitResponse(resp.get());
  85. }
  86. return status_code;
  87. }
  88. int HttpHandler::defaultRequestHandler() {
  89. int status_code = HTTP_STATUS_OK;
  90. http_handler* handler = NULL;
  91. if (service->api_handlers.size() != 0) {
  92. service->GetApi(req.get(), &handler);
  93. }
  94. if (handler) {
  95. status_code = invokeHttpHandler(handler);
  96. }
  97. else if (req->method == HTTP_GET || req->method == HTTP_HEAD) {
  98. // static handler
  99. if (service->staticHandler) {
  100. status_code = customHttpHandler(service->staticHandler);
  101. }
  102. else if (service->document_root.size() != 0) {
  103. status_code = defaultStaticHandler();
  104. }
  105. else {
  106. status_code = HTTP_STATUS_NOT_FOUND;
  107. }
  108. }
  109. else {
  110. // Not Implemented
  111. status_code = HTTP_STATUS_NOT_IMPLEMENTED;
  112. }
  113. return status_code;
  114. }
  115. int HttpHandler::defaultStaticHandler() {
  116. // file service
  117. int status_code = HTTP_STATUS_OK;
  118. std::string path = req->Path();
  119. const char* req_path = path.c_str();
  120. // path safe check
  121. if (req_path[0] != '/' || strstr(req_path, "/../")) {
  122. return HTTP_STATUS_BAD_REQUEST;
  123. }
  124. std::string filepath = service->document_root + path;
  125. if (req_path[1] == '\0') {
  126. filepath += service->home_page;
  127. }
  128. bool is_dir = filepath.c_str()[filepath.size()-1] == '/';
  129. bool is_index_of = false;
  130. if (service->index_of.size() != 0 && hv_strstartswith(req_path, service->index_of.c_str())) {
  131. is_index_of = true;
  132. }
  133. if (!is_dir || is_index_of) {
  134. FileCache::OpenParam param;
  135. bool has_range = req->headers.find("Range") != req->headers.end();
  136. param.need_read = !(req->method == HTTP_HEAD || has_range);
  137. param.path = req_path;
  138. fc = files->Open(filepath.c_str(), &param);
  139. if (fc == NULL) {
  140. status_code = HTTP_STATUS_NOT_FOUND;
  141. if (param.error == ERR_OVER_LIMIT) {
  142. if (service->largeFileHandler) {
  143. status_code = customHttpHandler(service->largeFileHandler);
  144. }
  145. }
  146. }
  147. } else {
  148. status_code = HTTP_STATUS_NOT_FOUND;
  149. }
  150. if (fc) {
  151. // Not Modified
  152. auto iter = req->headers.find("if-not-match");
  153. if (iter != req->headers.end() &&
  154. strcmp(iter->second.c_str(), fc->etag) == 0) {
  155. status_code = HTTP_STATUS_NOT_MODIFIED;
  156. fc = NULL;
  157. }
  158. else {
  159. iter = req->headers.find("if-modified-since");
  160. if (iter != req->headers.end() &&
  161. strcmp(iter->second.c_str(), fc->last_modified) == 0) {
  162. status_code = HTTP_STATUS_NOT_MODIFIED;
  163. fc = NULL;
  164. }
  165. }
  166. }
  167. return status_code;
  168. }
  169. int HttpHandler::defaultErrorHandler() {
  170. // error page
  171. if (service->error_page.size() != 0) {
  172. std::string filepath = service->document_root + '/' + service->error_page;
  173. FileCache::OpenParam param;
  174. fc = files->Open(filepath.c_str(), &param);
  175. }
  176. // status page
  177. if (fc == NULL && resp->body.size() == 0) {
  178. resp->content_type = TEXT_HTML;
  179. make_http_status_page(resp->status_code, resp->body);
  180. }
  181. return 0;
  182. }
  183. int HttpHandler::FeedRecvData(const char* data, size_t len) {
  184. int nfeed = 0;
  185. if (protocol == HttpHandler::WEBSOCKET) {
  186. nfeed = ws->parser->FeedRecvData(data, len);
  187. if (nfeed != len) {
  188. hloge("[%s:%d] websocket parse error!", ip, port);
  189. }
  190. } else {
  191. if (state != WANT_RECV) {
  192. Reset();
  193. }
  194. nfeed = parser->FeedRecvData(data, len);
  195. if (nfeed != len) {
  196. hloge("[%s:%d] http parse error: %s", ip, port, parser->StrError(parser->GetError()));
  197. }
  198. }
  199. return nfeed;
  200. }
  201. int HttpHandler::GetSendData(char** data, size_t* len) {
  202. if (state == HANDLE_CONTINUE) {
  203. return 0;
  204. }
  205. HttpRequest* pReq = req.get();
  206. HttpResponse* pResp = resp.get();
  207. if (protocol == HTTP_V1) {
  208. switch(state) {
  209. case WANT_RECV:
  210. if (parser->IsComplete()) state = WANT_SEND;
  211. else return 0;
  212. case HANDLE_END:
  213. state = WANT_SEND;
  214. case WANT_SEND:
  215. state = SEND_HEADER;
  216. case SEND_HEADER:
  217. {
  218. int content_length = 0;
  219. const char* content = NULL;
  220. // HEAD
  221. if (pReq->method == HTTP_HEAD) {
  222. if (fc) {
  223. pResp->headers["Accept-Ranges"] = "bytes";
  224. pResp->headers["Content-Length"] = hv::to_string(fc->st.st_size);
  225. } else {
  226. pResp->headers["Content-Type"] = "text/html";
  227. pResp->headers["Content-Length"] = "0";
  228. }
  229. state = SEND_DONE;
  230. goto return_nobody;
  231. }
  232. // File service
  233. if (fc) {
  234. long from, to, total;
  235. int nread;
  236. // Range:
  237. if (pReq->GetRange(from, to)) {
  238. HFile file;
  239. if (file.open(fc->filepath.c_str(), "rb") != 0) {
  240. pResp->status_code = HTTP_STATUS_NOT_FOUND;
  241. state = SEND_DONE;
  242. goto return_nobody;
  243. }
  244. total = file.size();
  245. if (to == 0 || to >= total) to = total - 1;
  246. pResp->content_length = to - from + 1;
  247. nread = file.readrange(body, from, to);
  248. if (nread != pResp->content_length) {
  249. pResp->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
  250. state = SEND_DONE;
  251. goto return_nobody;
  252. }
  253. pResp->status_code = HTTP_STATUS_PARTIAL_CONTENT;
  254. pResp->SetRange(from, to, total);
  255. state = SEND_BODY;
  256. goto return_header;
  257. }
  258. // FileCache
  259. // NOTE: no copy filebuf, more efficient
  260. header = pResp->Dump(true, false);
  261. fc->prepend_header(header.c_str(), header.size());
  262. *data = fc->httpbuf.base;
  263. *len = fc->httpbuf.len;
  264. state = SEND_DONE;
  265. return *len;
  266. }
  267. // API service
  268. content_length = pResp->ContentLength();
  269. content = (const char*)pResp->Content();
  270. if (content) {
  271. if (content_length > (1 << 20)) {
  272. state = SEND_BODY;
  273. goto return_header;
  274. } else {
  275. // NOTE: header+body in one package if <= 1M
  276. header = pResp->Dump(true, false);
  277. header.append(content, content_length);
  278. state = SEND_DONE;
  279. goto return_header;
  280. }
  281. } else {
  282. state = SEND_DONE;
  283. goto return_header;
  284. }
  285. return_nobody:
  286. pResp->content_length = 0;
  287. return_header:
  288. if (header.empty()) header = pResp->Dump(true, false);
  289. *data = (char*)header.c_str();
  290. *len = header.size();
  291. return *len;
  292. }
  293. case SEND_BODY:
  294. {
  295. if (body.empty()) {
  296. *data = (char*)pResp->Content();
  297. *len = pResp->ContentLength();
  298. } else {
  299. *data = (char*)body.c_str();
  300. *len = body.size();
  301. }
  302. state = SEND_DONE;
  303. return *len;
  304. }
  305. case SEND_DONE:
  306. {
  307. // NOTE: remove file cache if > 16M
  308. if (fc && fc->filebuf.len > (1 << 24)) {
  309. files->Close(fc);
  310. }
  311. fc = NULL;
  312. header.clear();
  313. body.clear();
  314. return 0;
  315. }
  316. default:
  317. return 0;
  318. }
  319. } else if (protocol == HTTP_V2) {
  320. return parser->GetSendData(data, len);
  321. }
  322. return 0;
  323. }