Просмотр исходного кода

http_handler(const HttpContextPtr&)

ithewei 4 лет назад
Родитель
Сommit
b46921078b

+ 4 - 4
evpp/Channel.h

@@ -79,17 +79,17 @@ public:
     }
 
     int startRead() {
-        if (!isOpened()) return 0;
+        if (!isOpened()) return -1;
         return hio_read_start(io_);
     }
 
     int stopRead() {
-        if (!isOpened()) return 0;
+        if (!isOpened()) return -1;
         return hio_read_stop(io_);
     }
 
     int write(const void* data, int size) {
-        if (!isOpened()) return 0;
+        if (!isOpened()) return -1;
         return hio_write(io_, data, size);
     }
 
@@ -102,7 +102,7 @@ public:
     }
 
     int close(bool async = false) {
-        if (!isOpened()) return 0;
+        if (!isOpened()) return -1;
         if (async) {
             return hio_close_async(io_);
         }

+ 3 - 1
examples/httpd/handler.h

@@ -92,7 +92,9 @@ public:
                     ctx->writer->close();
                     break;
                 }
-                ctx->writer->WriteBody(buf, readbytes);
+                if (ctx->writer->WriteBody(buf, readbytes) < 0) {
+                    break;
+                }
                 total_readbytes += readbytes;
             }
             ctx->writer->End();

+ 10 - 0
examples/httpd/router.h

@@ -47,6 +47,16 @@ public:
             return 200;
         });
 
+        // curl -v http://ip:port/service
+        router.GET("/service", [](const HttpContextPtr& ctx) {
+            ctx->response->json["base_url"] = ctx->service->base_url;
+            ctx->response->json["doucument_root"] = ctx->service->document_root;
+            ctx->response->json["home_page"] = ctx->service->home_page;
+            ctx->response->json["error_page"] = ctx->service->error_page;
+            ctx->response->json["index_of"] = ctx->service->index_of;
+            return 200;
+        });
+
         // curl -v http://ip:port/echo -d "hello,world!"
         router.POST("/echo", [](HttpRequest* req, HttpResponse* resp) {
             resp->content_type = req->content_type;

+ 2 - 0
getting_started.sh

@@ -45,6 +45,8 @@ cmd="bin/curl -v localhost:8080/html/index.html" && run_cmd
 
 cmd="bin/curl -v localhost:8080/get?env=1" && run_cmd
 
+cmd="bin/curl -v localhost:8080/service" && run_cmd
+
 cmd="bin/curl -v localhost:8080/wildcard/test" && run_cmd
 
 cmd="bin/curl -v localhost:8080/echo -d 'hello,world!'" && echo_cmd

+ 9 - 1
http/server/HttpHandler.cpp

@@ -78,9 +78,10 @@ int HttpHandler::defaultRequestHandler() {
     int status_code = HTTP_STATUS_OK;
     http_sync_handler sync_handler = NULL;
     http_async_handler async_handler = NULL;
+    http_handler ctx_handler = NULL;
 
     if (service->api_handlers.size() != 0) {
-        service->GetApi(req.get(), &sync_handler, &async_handler);
+        service->GetApi(req.get(), &sync_handler, &async_handler, &ctx_handler);
     }
 
     if (sync_handler) {
@@ -95,6 +96,13 @@ int HttpHandler::defaultRequestHandler() {
         async_handler(req, writer);
         status_code = 0;
     }
+    else if (ctx_handler) {
+        // HttpContext handler
+        status_code = customHttpHandler(ctx_handler);
+        if (status_code != 0) {
+            return status_code;
+        }
+    }
     else if (req->method == HTTP_GET || req->method == HTTP_HEAD) {
         // static handler
         if (service->staticHandler) {

+ 5 - 0
http/server/HttpResponseWriter.h

@@ -86,6 +86,11 @@ public:
 
     int End(const char* buf = NULL, int len = -1) {
         if (state == SEND_END) return 0;
+        if (!isConnected()) {
+            state = SEND_END;
+            return -1;
+        }
+
         int ret = 0;
         if (buf) {
             ret = WriteBody(buf, len);

+ 6 - 0
http/server/HttpServer.cpp

@@ -109,6 +109,9 @@ static void on_recv(hio_t* io, void* _buf, int readbytes) {
             return;
         }
         handler->writer.reset(new HttpResponseWriter(io, handler->resp));
+        if (handler->writer) {
+            handler->writer->status = SocketChannel::CONNECTED;
+        }
     }
 
     int nfeed = handler->FeedRecvData(buf, readbytes);
@@ -242,6 +245,9 @@ static void on_close(hio_t* io) {
             // onclose
             handler->WebSocketOnClose();
         }
+        if (handler->writer) {
+            handler->writer->status = SocketChannel::DISCONNECTED;
+        }
         hevent_set_userdata(io, NULL);
         delete handler;
     }

+ 16 - 10
http/server/HttpService.cpp

@@ -2,7 +2,7 @@
 
 #include "hbase.h" // import strendswith
 
-void HttpService::AddApi(const char* path, http_method method, http_sync_handler handler, http_async_handler async_handler) {
+void HttpService::AddApi(const char* path, http_method method, http_sync_handler sync_handler, http_async_handler async_handler, http_handler handler) {
     std::shared_ptr<http_method_handlers> method_handlers = NULL;
     auto iter = api_handlers.find(path);
     if (iter == api_handlers.end()) {
@@ -16,16 +16,17 @@ void HttpService::AddApi(const char* path, http_method method, http_sync_handler
     for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
         if (iter->method == method) {
             // update
-            iter->sync_handler = handler;
+            iter->sync_handler = sync_handler;
             iter->async_handler = async_handler;
+            iter->handler = handler;
             return;
         }
     }
     // add
-    method_handlers->push_back(http_method_handler(method, handler, async_handler));
+    method_handlers->push_back(http_method_handler(method, sync_handler, async_handler, handler));
 }
 
-int HttpService::GetApi(const char* url, http_method method, http_sync_handler* handler, http_async_handler* async_handler) {
+int HttpService::GetApi(const char* url, http_method method, http_sync_handler* sync_handler, http_async_handler* async_handler, http_handler* handler) {
     // {base_url}/path?query
     const char* s = url;
     const char* b = base_url.c_str();
@@ -39,15 +40,17 @@ int HttpService::GetApi(const char* url, http_method method, http_sync_handler*
     std::string path = std::string(s, e);
     auto iter = api_handlers.find(path);
     if (iter == api_handlers.end()) {
-        if (handler) *handler = NULL;
+        if (sync_handler) *sync_handler = NULL;
         if (async_handler) *async_handler = NULL;
+        if (handler) *handler = NULL;
         return HTTP_STATUS_NOT_FOUND;
     }
     auto method_handlers = iter->second;
     for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
         if (iter->method == method) {
-            if (handler) *handler = iter->sync_handler;
+            if (sync_handler) *sync_handler = iter->sync_handler;
             if (async_handler) *async_handler = iter->async_handler;
+            if (handler) *handler = iter->handler;
             return 0;
         }
     }
@@ -56,7 +59,7 @@ int HttpService::GetApi(const char* url, http_method method, http_sync_handler*
     return HTTP_STATUS_METHOD_NOT_ALLOWED;
 }
 
-int HttpService::GetApi(HttpRequest* req, http_sync_handler* handler, http_async_handler* async_handler) {
+int HttpService::GetApi(HttpRequest* req, http_sync_handler* sync_handler, http_async_handler* async_handler, http_handler* handler) {
     // {base_url}/path?query
     const char* s = req->path.c_str();
     const char* b = base_url.c_str();
@@ -115,20 +118,23 @@ int HttpService::GetApi(HttpRequest* req, http_sync_handler* handler, http_async
                         // RESTful /:field/ => req->query_params[field]
                         req->query_params[param.first] = param.second;
                     }
-                    if (handler) *handler = iter->sync_handler;
+                    if (sync_handler) *sync_handler = iter->sync_handler;
                     if (async_handler) *async_handler = iter->async_handler;
+                    if (handler) *handler = iter->handler;
                     return 0;
                 }
             }
 
             if (params.size() == 0) {
-                if (handler) *handler = NULL;
+                if (sync_handler) *sync_handler = NULL;
                 if (async_handler) *async_handler = NULL;
+                if (handler) *handler = NULL;
                 return HTTP_STATUS_METHOD_NOT_ALLOWED;
             }
         }
     }
-    if (handler) *handler = NULL;
+    if (sync_handler) *sync_handler = NULL;
     if (async_handler) *async_handler = NULL;
+    if (handler) *handler = NULL;
     return HTTP_STATUS_NOT_FOUND;
 }

+ 57 - 16
http/server/HttpService.h

@@ -26,17 +26,30 @@
 typedef std::function<int(HttpRequest* req, HttpResponse* resp)>                            http_sync_handler;
 typedef std::function<void(const HttpRequestPtr& req, const HttpResponseWriterPtr& writer)> http_async_handler;
 
+struct HttpService;
+struct HV_EXPORT HttpContext {
+    HttpService*            service;
+    HttpRequestPtr          request;
+    HttpResponsePtr         response;
+    HttpResponseWriterPtr   writer;
+};
+typedef std::shared_ptr<HttpContext>                    HttpContextPtr;
+typedef std::function<int(const HttpContextPtr& ctx)>   http_handler;
+
 struct http_method_handler {
     http_method         method;
     http_sync_handler   sync_handler;
     http_async_handler  async_handler;
+    http_handler        handler;
     http_method_handler(http_method m = HTTP_POST,
                         http_sync_handler s = NULL,
-                        http_async_handler a = NULL)
+                        http_async_handler a = NULL,
+                        http_handler h = NULL)
     {
         method = m;
         sync_handler = std::move(s);
         async_handler = std::move(a);
+        handler = std::move(h);
     }
 };
 // method => http_method_handler
@@ -44,16 +57,6 @@ typedef std::list<http_method_handler>                                  http_met
 // path => http_method_handlers
 typedef std::map<std::string, std::shared_ptr<http_method_handlers>>    http_api_handlers;
 
-struct HttpService;
-struct HV_EXPORT HttpContext {
-    HttpService*            service;
-    HttpRequestPtr          request;
-    HttpResponsePtr         response;
-    HttpResponseWriterPtr   writer;
-};
-typedef std::shared_ptr<HttpContext>                    HttpContextPtr;
-typedef std::function<int(const HttpContextPtr& ctx)>   http_handler;
-
 struct HV_EXPORT HttpService {
     // preprocessor -> processor -> postprocessor
     http_sync_handler   preprocessor;
@@ -94,11 +97,20 @@ struct HV_EXPORT HttpService {
         errorHandler = NULL;
     }
 
-    void AddApi(const char* path, http_method method, http_sync_handler handler = NULL, http_async_handler async_handler = NULL);
+    void AddApi(const char* path, http_method method,
+            http_sync_handler sync_handler = NULL,
+            http_async_handler async_handler = NULL,
+            http_handler handler = NULL);
     // @retval 0 OK, else HTTP_STATUS_NOT_FOUND, HTTP_STATUS_METHOD_NOT_ALLOWED
-    int GetApi(const char* url, http_method method, http_sync_handler* handler = NULL, http_async_handler* async_handler = NULL);
+    int GetApi(const char* url, http_method method,
+            http_sync_handler* sync_handler = NULL,
+            http_async_handler* async_handler = NULL,
+            http_handler* handler = NULL);
     // RESTful API /:field/ => req->query_params["field"]
-    int GetApi(HttpRequest* req, http_sync_handler* handler = NULL, http_async_handler* async_handler = NULL);
+    int GetApi(HttpRequest* req,
+            http_sync_handler* sync_handler = NULL,
+            http_async_handler* async_handler = NULL,
+            http_handler* handler = NULL);
 
     StringList Paths() {
         StringList paths;
@@ -110,10 +122,13 @@ struct HV_EXPORT HttpService {
 
     // github.com/gin-gonic/gin
     void Handle(const char* httpMethod, const char* relativePath, http_sync_handler handlerFunc) {
-        AddApi(relativePath, http_method_enum(httpMethod), handlerFunc, NULL);
+        AddApi(relativePath, http_method_enum(httpMethod), handlerFunc, NULL, NULL);
     }
     void Handle(const char* httpMethod, const char* relativePath, http_async_handler handlerFunc) {
-        AddApi(relativePath, http_method_enum(httpMethod), NULL, handlerFunc);
+        AddApi(relativePath, http_method_enum(httpMethod), NULL, handlerFunc, NULL);
+    }
+    void Handle(const char* httpMethod, const char* relativePath, http_handler handlerFunc) {
+        AddApi(relativePath, http_method_enum(httpMethod), NULL, NULL, handlerFunc);
     }
 
     // HEAD
@@ -123,6 +138,9 @@ struct HV_EXPORT HttpService {
     void HEAD(const char* relativePath, http_async_handler handlerFunc) {
         Handle("HEAD", relativePath, handlerFunc);
     }
+    void HEAD(const char* relativePath, http_handler handlerFunc) {
+        Handle("HEAD", relativePath, handlerFunc);
+    }
 
     // GET
     void GET(const char* relativePath, http_sync_handler handlerFunc) {
@@ -131,6 +149,9 @@ struct HV_EXPORT HttpService {
     void GET(const char* relativePath, http_async_handler handlerFunc) {
         Handle("GET", relativePath, handlerFunc);
     }
+    void GET(const char* relativePath, http_handler handlerFunc) {
+        Handle("GET", relativePath, handlerFunc);
+    }
 
     // POST
     void POST(const char* relativePath, http_sync_handler handlerFunc) {
@@ -139,6 +160,9 @@ struct HV_EXPORT HttpService {
     void POST(const char* relativePath, http_async_handler handlerFunc) {
         Handle("POST", relativePath, handlerFunc);
     }
+    void POST(const char* relativePath, http_handler handlerFunc) {
+        Handle("POST", relativePath, handlerFunc);
+    }
 
     // PUT
     void PUT(const char* relativePath, http_sync_handler handlerFunc) {
@@ -147,6 +171,9 @@ struct HV_EXPORT HttpService {
     void PUT(const char* relativePath, http_async_handler handlerFunc) {
         Handle("PUT", relativePath, handlerFunc);
     }
+    void PUT(const char* relativePath, http_handler handlerFunc) {
+        Handle("PUT", relativePath, handlerFunc);
+    }
 
     // DELETE
     // NOTE: Windows <winnt.h> #define DELETE as a macro, we have to replace DELETE with Delete.
@@ -156,6 +183,9 @@ struct HV_EXPORT HttpService {
     void Delete(const char* relativePath, http_async_handler handlerFunc) {
         Handle("DELETE", relativePath, handlerFunc);
     }
+    void Delete(const char* relativePath, http_handler handlerFunc) {
+        Handle("DELETE", relativePath, handlerFunc);
+    }
 
     // PATCH
     void PATCH(const char* relativePath, http_sync_handler handlerFunc) {
@@ -164,6 +194,9 @@ struct HV_EXPORT HttpService {
     void PATCH(const char* relativePath, http_async_handler handlerFunc) {
         Handle("PATCH", relativePath, handlerFunc);
     }
+    void PATCH(const char* relativePath, http_handler handlerFunc) {
+        Handle("PATCH", relativePath, handlerFunc);
+    }
 
     // Any
     void Any(const char* relativePath, http_sync_handler handlerFunc) {
@@ -182,6 +215,14 @@ struct HV_EXPORT HttpService {
         Handle("DELETE", relativePath, handlerFunc);
         Handle("PATCH", relativePath, handlerFunc);
     }
+    void Any(const char* relativePath, http_handler handlerFunc) {
+        Handle("HEAD", relativePath, handlerFunc);
+        Handle("GET", relativePath, handlerFunc);
+        Handle("POST", relativePath, handlerFunc);
+        Handle("PUT", relativePath, handlerFunc);
+        Handle("DELETE", relativePath, handlerFunc);
+        Handle("PATCH", relativePath, handlerFunc);
+    }
 };
 
 #endif // HV_HTTP_SERVICE_H_