1
0

HttpHandler.cpp 10 KB

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