HttpHandler.cpp 11 KB

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