1
0

HttpHandler.cpp 11 KB

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