ithewei 5 år sedan
förälder
incheckning
544c96beaf
6 ändrade filer med 89 tillägg och 41 borttagningar
  1. 3 1
      event/hloop.c
  2. 5 4
      event/hloop.h
  3. 49 10
      examples/httpd/http_api_test.h
  4. 1 1
      examples/nc.c
  5. 25 23
      http/server/HttpHandler.cpp
  6. 6 2
      http/server/HttpService.h

+ 3 - 1
event/hloop.c

@@ -261,7 +261,9 @@ int hloop_run(hloop_t* loop) {
             continue;
         }
         ++loop->loop_cnt;
-        if (loop->nactives == 0) break;
+        if (loop->nactives == 0 && loop->flags & HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS) {
+            break;
+        }
         hloop_process_events(loop);
         if (loop->flags & HLOOP_FLAG_RUN_ONCE) {
             break;

+ 5 - 4
event/hloop.h

@@ -88,12 +88,13 @@ typedef enum {
 } hio_type_e;
 
 // loop
-#define HLOOP_FLAG_RUN_ONCE    0x00000001
-#define HLOOP_FLAG_AUTO_FREE   0x00000002
+#define HLOOP_FLAG_RUN_ONCE                     0x00000001
+#define HLOOP_FLAG_AUTO_FREE                    0x00000002
+#define HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS   0x00000004
 hloop_t* hloop_new(int flags DEFAULT(HLOOP_FLAG_AUTO_FREE));
-// WARN: Not allow to call hloop_free when HLOOP_INIT_FLAG_AUTO_FREE set.
+// WARN: Forbid to call hloop_free if HLOOP_INIT_FLAG_AUTO_FREE set.
 void hloop_free(hloop_t** pp);
-// NOTE: when no active events, loop will quit.
+// NOTE: when no active events, loop will quit if HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS set.
 int hloop_run(hloop_t* loop);
 int hloop_stop(hloop_t* loop);
 int hloop_pause(hloop_t* loop);

+ 49 - 10
examples/httpd/http_api_test.h

@@ -5,6 +5,7 @@
 
 // XXX(path, method, handler)
 #define HTTP_API_MAP(XXX) \
+    XXX("/login",   POST,   http_api_login)     \
     XXX("/hello",   GET,    http_api_hello)     \
     XXX("/query",   GET,    http_api_query)     \
     XXX("/echo",    POST,   http_api_echo)      \
@@ -27,6 +28,23 @@ inline int http_api_preprocessor(HttpRequest* req, HttpResponse* res) {
     //printf("%s\n", req->Dump(true, true).c_str());
     req->ParseBody();
     res->content_type = APPLICATION_JSON;
+#if 0
+    // authentication sample code
+    if (strcmp(req->path.c_str(), DEFAULT_BASE_URL "/login") != 0) {
+        string token = req->GetHeader("token");
+        if (token.empty()) {
+            response_status(res, 10011, "Miss token");
+            res->DumpBody();
+            return HTTP_STATUS_UNAUTHORIZED;
+        }
+        else if (strcmp(token.c_str(), "abcdefg") != 0) {
+            response_status(res, 10012, "Token wrong");
+            res->DumpBody();
+            return HTTP_STATUS_UNAUTHORIZED;
+        }
+        return 0;
+    }
+#endif
     return 0;
 }
 
@@ -36,7 +54,33 @@ inline int http_api_postprocessor(HttpRequest* req, HttpResponse* res) {
     return 0;
 }
 
+inline int http_api_login(HttpRequest* req, HttpResponse* res) {
+    int ret = 0;
+    string username = req->GetString("username");
+    string password = req->GetString("password");
+    if (username.empty() || password.empty()) {
+        response_status(res, 10001, "Miss username or password");
+        ret = HTTP_STATUS_BAD_REQUEST;
+    }
+    else if (strcmp(username.c_str(), "admin") != 0) {
+        response_status(res, 10002, "Username not exist");
+        ret = HTTP_STATUS_BAD_REQUEST;
+    }
+    else if (strcmp(password.c_str(), "123456") != 0) {
+        response_status(res, 10003, "Password wrong");
+        ret = HTTP_STATUS_BAD_REQUEST;
+    }
+    else {
+        res->Set("token", "abcdefg");
+        response_status(res, 0, "Login succeed.");
+        ret = HTTP_STATUS_OK;
+    }
+    res->DumpBody();
+    return ret;
+}
+
 inline int http_api_hello(HttpRequest* req, HttpResponse* res) {
+    res->content_type = TEXT_PLAIN;
     res->body = "hello";
     return 0;
 }
@@ -59,8 +103,7 @@ inline int http_api_echo(HttpRequest* req, HttpResponse* res) {
 
 inline int http_api_kv(HttpRequest*req, HttpResponse* res) {
     if (req->content_type != APPLICATION_URLENCODED) {
-        res->status_code = HTTP_STATUS_BAD_REQUEST;
-        return 0;
+        return HTTP_STATUS_BAD_REQUEST;
     }
     res->content_type = APPLICATION_URLENCODED;
     res->kv = req->kv;
@@ -69,8 +112,7 @@ inline int http_api_kv(HttpRequest*req, HttpResponse* res) {
 
 inline int http_api_json(HttpRequest* req, HttpResponse* res) {
     if (req->content_type != APPLICATION_JSON) {
-        res->status_code = HTTP_STATUS_BAD_REQUEST;
-        return 0;
+        return HTTP_STATUS_BAD_REQUEST;
     }
     res->content_type = APPLICATION_JSON;
     res->json = req->json;
@@ -79,8 +121,7 @@ inline int http_api_json(HttpRequest* req, HttpResponse* res) {
 
 inline int http_api_form(HttpRequest* req, HttpResponse* res) {
     if (req->content_type != MULTIPART_FORM_DATA) {
-        res->status_code = HTTP_STATUS_BAD_REQUEST;
-        return 0;
+        return HTTP_STATUS_BAD_REQUEST;
     }
     res->content_type = MULTIPART_FORM_DATA;
     res->form = req->form;
@@ -89,8 +130,7 @@ inline int http_api_form(HttpRequest* req, HttpResponse* res) {
 
 inline int http_api_upload(HttpRequest* req, HttpResponse* res) {
     if (req->content_type != MULTIPART_FORM_DATA) {
-        res->status_code = HTTP_STATUS_BAD_REQUEST;
-        return 0;
+        return HTTP_STATUS_BAD_REQUEST;
     }
     FormData file = req->form["file"];
     string filepath("html/uploads/");
@@ -107,8 +147,7 @@ inline int http_api_upload(HttpRequest* req, HttpResponse* res) {
 
 inline int http_api_grpc(HttpRequest* req, HttpResponse* res) {
     if (req->content_type != APPLICATION_GRPC) {
-        res->status_code = HTTP_STATUS_BAD_REQUEST;
-        return 0;
+        return HTTP_STATUS_BAD_REQUEST;
     }
     // parse protobuf: ParseFromString
     // req->body;

+ 1 - 1
examples/nc.c

@@ -98,7 +98,7 @@ Examples: nc 127.0.0.1 80\n\
 
     HV_MEMCHECK;
 
-    hloop_t* loop = hloop_new(0);
+    hloop_t* loop = hloop_new(HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS);
 
     // stdin
     stdinio = hread(loop, 0, recvbuf, RECV_BUFSIZE, on_stdin);

+ 25 - 23
http/server/HttpHandler.cpp

@@ -5,32 +5,33 @@
 
 int HttpHandler::HandleRequest() {
     // preprocessor -> api -> web -> postprocessor
-    // preprocessor
+
+    int ret = 0;
+    http_api_handler api = NULL;
+
     req.ParseUrl();
     req.client_addr.ip = ip;
     req.client_addr.port = port;
+
+preprocessor:
     if (service->preprocessor) {
-        if (service->preprocessor(&req, &res) == HANDLE_DONE) {
-            return HANDLE_DONE;
+        ret = service->preprocessor(&req, &res);
+        if (ret != 0) {
+            goto make_http_status_page;
         }
     }
 
-    http_api_handler api = NULL;
-    int ret = 0;
     if (service->api_handlers.size() != 0) {
-        ret = service->GetApi(&req, &api);
+        service->GetApi(&req, &api);
     }
 
     if (api) {
         // api service
-        if (api(&req, &res) == HANDLE_DONE) {
-            return HANDLE_DONE;
+        ret = api(&req, &res);
+        if (ret != 0) {
+            goto make_http_status_page;
         }
     }
-    else if (ret == HTTP_STATUS_METHOD_NOT_ALLOWED) {
-        // Method Not Allowed
-        res.status_code = HTTP_STATUS_METHOD_NOT_ALLOWED;
-    }
     else if (service->document_root.size() != 0 && req.method == HTTP_GET) {
         // web service
         // path safe check
@@ -54,21 +55,21 @@ int HttpHandler::HandleRequest() {
         }
         if (fc == NULL) {
             // Not Found
-            res.status_code = HTTP_STATUS_NOT_FOUND;
+            ret = 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;
+                ret = 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;
+                    ret = HTTP_STATUS_NOT_MODIFIED;
                     fc = NULL;
                 }
             }
@@ -76,11 +77,13 @@ int HttpHandler::HandleRequest() {
     }
     else {
         // Not Implemented
-        res.status_code = HTTP_STATUS_NOT_IMPLEMENTED;
+        ret = HTTP_STATUS_NOT_IMPLEMENTED;
     }
 
 make_http_status_page:
-    // html page
+    if (ret >= 100 && ret < 600) {
+        res.status_code = (http_status)ret;
+    }
     if (res.status_code >= 400 && res.body.size() == 0) {
         // error page
         if (service->error_page.size() != 0) {
@@ -96,8 +99,8 @@ make_http_status_page:
         }
     }
 
-    // file
     if (fc) {
+        // link file cache
         res.content = (unsigned char*)fc->filebuf.base;
         res.content_length = fc->filebuf.len;
         if (fc->content_type && *fc->content_type != '\0') {
@@ -111,11 +114,10 @@ make_http_status_page:
         res.headers["Etag"] = fc->etag;
     }
 
-    // postprocessor
+postprocessor:
     if (service->postprocessor) {
-        if (service->postprocessor(&req, &res) == HANDLE_DONE) {
-            return HANDLE_DONE;
-        }
+        ret = service->postprocessor(&req, &res);
     }
-    return HANDLE_DONE;
+
+    return ret;
 }

+ 6 - 2
http/server/HttpService.h

@@ -13,8 +13,12 @@
 #define DEFAULT_DOCUMENT_ROOT   "/var/www/html"
 #define DEFAULT_HOME_PAGE       "index.html"
 
-#define HANDLE_CONTINUE 0
-#define HANDLE_DONE     1
+/*
+ * @param[in] req: parsed structured http request
+ * @param[out] res: structured http response
+ * @return  0: handle continue
+ *          http_status_code: handle done
+ */
 typedef int (*http_api_handler)(HttpRequest* req, HttpResponse* res);
 
 struct http_method_handler {