Selaa lähdekoodia

Paths, wildcard *

ithewei 5 vuotta sitten
vanhempi
commit
80a6b4d2f2
2 muutettua tiedostoa jossa 45 lisäystä ja 18 poistoa
  1. 33 17
      http/server/HttpService.cpp
  2. 12 1
      http/server/HttpService.h

+ 33 - 17
http/server/HttpService.cpp

@@ -1,5 +1,7 @@
 #include "HttpService.h"
 
+#include "hbase.h" // import strendswith
+
 void HttpService::AddApi(const char* path, http_method method, http_api_handler handler) {
     std::shared_ptr<http_method_handlers> method_handlers = NULL;
     auto iter = api_handlers.find(path);
@@ -63,34 +65,48 @@ int HttpService::GetApi(HttpRequest* req, http_api_handler* handler) {
 
     std::string path = std::string(s, e);
     const char *kp, *ks, *vp, *vs;
+    bool match;
     for (auto iter = api_handlers.begin(); iter != api_handlers.end(); ++iter) {
         kp = iter->first.c_str();
         vp = path.c_str();
-
-        // RESTful API
+        match = false;
         std::map<std::string, std::string> params;
-        while (*kp && *vp && *kp == *vp) {
-            if (kp[0] == '/' && kp[1] == ':') {
-                kp += 2;
-                ks = kp;
-                while (*kp && *kp != '/') {++kp;}
-                vp += 1;
-                vs = vp;
-                while (*vp && *vp != '/') {++vp;}
-                params[std::string(ks, kp-ks)] = std::string(vs, vp-vs);
-            }
-            else {
-                ++kp;
-                ++vp;
+
+        while (*kp && *vp) {
+            if (kp[0] == '*') {
+                // wildcard *
+                if (strendswith(vp, kp+1)) {
+                    match = true;
+                }
+                break;
+            } else if (*kp == *vp) {
+                if (kp[0] == '/' && kp[1] == ':') {
+                    // RESTful /:field/
+                    kp += 2;
+                    ks = kp;
+                    while (*kp && *kp != '/') {++kp;}
+                    vp += 1;
+                    vs = vp;
+                    while (*vp && *vp != '/') {++vp;}
+                    params[std::string(ks, kp-ks)] = std::string(vs, vp-vs);
+                } else {
+                    ++kp;
+                    ++vp;
+                }
+            } else {
+                match = false;
+                break;
             }
         }
 
-        if (*kp == '\0' && *vp == '\0') {
+        match = match ? match : (*kp == '\0' && *vp == '\0');
+
+        if (match) {
             auto method_handlers = iter->second;
             for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
                 if (iter->method == req->method) {
                     for (auto& param : params) {
-                        // RESTful /:field/ => req->query_params
+                        // RESTful /:field/ => req->query_params[field]
                         req->query_params[param.first] = param.second;
                     }
                     *handler = iter->handler;

+ 12 - 1
http/server/HttpService.h

@@ -5,6 +5,7 @@
 #include <map>
 #include <list>
 #include <memory>
+#include <functional>
 
 #include "hexport.h"
 #include "HttpMessage.h"
@@ -19,7 +20,9 @@
  * @return  0: handle continue
  *          http_status_code: handle done
  */
-typedef int (*http_api_handler)(HttpRequest* req, HttpResponse* res);
+// typedef int (*http_api_handler)(HttpRequest* req, HttpResponse* res);
+// NOTE: use std::function/std::bind is more convenient and more flexible.
+typedef std::function<int(HttpRequest* req, HttpResponse* resp)> http_api_handler;
 
 struct http_method_handler {
     http_method         method;
@@ -62,6 +65,14 @@ struct HV_EXPORT HttpService {
     // RESTful API /:field/ => req->query_params["field"]
     int GetApi(HttpRequest* req, http_api_handler* handler);
 
+    StringList Paths() {
+        StringList paths;
+        for (auto& pair : api_handlers) {
+            paths.emplace_back(pair.first);
+        }
+        return paths;
+    }
+
     // github.com/gin-gonic/gin
     void Handle(const char* httpMethod, const char* relativePath, http_api_handler handlerFunc) {
         AddApi(relativePath, http_method_enum(httpMethod), handlerFunc);