| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- #ifndef HTTP_HANDLER_H_
- #define HTTP_HANDLER_H_
- #include "HttpService.h"
- #include "HttpParser.h"
- #include "FileCache.h"
- #include "http_page.h"
- #include "hloop.h"
- #define HTTP_KEEPALIVE_TIMEOUT 75 // s
- static inline void on_keepalive_timeout(htimer_t* timer) {
- hio_t* io = (hio_t*)timer->userdata;
- hclose(io);
- }
- class HttpHandler {
- public:
- HttpService* service;
- FileCache* files;
- char srcip[64];
- int srcport;
- HttpParser parser;
- HttpRequest req;
- HttpResponse res;
- file_cache_t* fc;
- hio_t* io;
- htimer_t* keepalive_timer;
- HttpHandler() {
- service = NULL;
- files = NULL;
- io = NULL;
- keepalive_timer = NULL;
- init();
- }
- ~HttpHandler() {
- if (keepalive_timer) {
- htimer_del(keepalive_timer);
- keepalive_timer = NULL;
- }
- }
- void init() {
- fc = NULL;
- parser.parser_request_init(&req);
- }
- void reset() {
- init();
- req.reset();
- res.reset();
- }
- void keepalive() {
- if (keepalive_timer == NULL) {
- keepalive_timer = htimer_add(io->loop, on_keepalive_timeout, HTTP_KEEPALIVE_TIMEOUT*1000, 1);
- keepalive_timer->userdata = io;
- }
- else {
- htimer_reset(keepalive_timer);
- }
- }
- int handle_request() {
- // preprocessor -> api -> web -> postprocessor
- // preprocessor
- if (service->preprocessor) {
- if (service->preprocessor(&req, &res) == HANDLE_DONE) {
- return HANDLE_DONE;
- }
- }
- http_api_handler api = NULL;
- int ret = service->GetApi(req.url.c_str(), req.method, &api);
- if (api) {
- // api service
- if (api(&req, &res) == HANDLE_DONE) {
- return HANDLE_DONE;
- }
- }
- else if (ret == HTTP_STATUS_METHOD_NOT_ALLOWED) {
- // Method Not Allowed
- res.status_code = HTTP_STATUS_METHOD_NOT_ALLOWED;
- }
- else if (req.method == HTTP_GET) {
- // web service
- std::string filepath = service->document_root;
- filepath += req.url.c_str();
- if (strcmp(req.url.c_str(), "/") == 0) {
- filepath += service->home_page;
- }
- if (filepath.c_str()[filepath.size()-1] != '/' ||
- (service->index_of.size() != 0 &&
- req.url.size() >= service->index_of.size() &&
- strnicmp(req.url.c_str(), service->index_of.c_str(), service->index_of.size()) == 0)) {
- fc = files->Open(filepath.c_str(), (void*)req.url.c_str());
- }
- if (fc == NULL) {
- // Not Found
- res.status_code = HTTP_STATUS_NOT_FOUND;
- }
- else {
- // Not Modified
- auto iter = req.headers.find("if-not-match");
- if (iter != req.headers.end() &&
- strcmp(iter->second.c_str(), fc->etag) == 0) {
- res.status_code = HTTP_STATUS_NOT_MODIFIED;
- fc = NULL;
- }
- else {
- iter = req.headers.find("if-modified-since");
- if (iter != req.headers.end() &&
- strcmp(iter->second.c_str(), fc->last_modified) == 0) {
- res.status_code = HTTP_STATUS_NOT_MODIFIED;
- fc = NULL;
- }
- }
- }
- }
- else {
- // Not Implemented
- res.status_code = HTTP_STATUS_NOT_IMPLEMENTED;
- }
- // html page
- if (res.status_code >= 400 && res.body.size() == 0) {
- // error page
- if (service->error_page.size() != 0) {
- std::string filepath = service->document_root;
- filepath += '/';
- filepath += service->error_page;
- fc = files->Open(filepath.c_str(), NULL);
- }
- // status page
- if (fc == NULL && res.body.size() == 0) {
- res.content_type = TEXT_HTML;
- make_http_status_page(res.status_code, res.body);
- }
- }
- // file
- if (fc) {
- if (fc->content_type && *fc->content_type != '\0') {
- res.headers["Content-Type"] = fc->content_type;
- }
- res.headers["Content-Length"] = std::to_string(fc->filebuf.len);
- res.headers["Last-Modified"] = fc->last_modified;
- res.headers["Etag"] = fc->etag;
- }
- // postprocessor
- if (service->postprocessor) {
- if (service->postprocessor(&req, &res) == HANDLE_DONE) {
- return HANDLE_DONE;
- }
- }
- return HANDLE_DONE;
- }
- };
- #endif // HTTP_HANDLER_H_
|