emsApplication/3rdPartner/libhv/http/server/HttpService.cpp

210 lines
6.1 KiB
C++

#include "HttpService.h"
#include "HttpMiddleware.h"
#include "hbase.h" // import hv_strendswith
namespace hv {
void HttpService::AddRoute(const char* path, http_method method, const http_handler& handler) {
std::shared_ptr<http_method_handlers> method_handlers = NULL;
auto iter = pathHandlers.find(path);
if (iter == pathHandlers.end()) {
// add path
method_handlers = std::make_shared<http_method_handlers>();
pathHandlers[path] = method_handlers;
}
else {
method_handlers = iter->second;
}
for (auto iter = method_handlers->begin(); iter != method_handlers->end(); ++iter) {
if (iter->method == method) {
// update
iter->handler = handler;
return;
}
}
// add
method_handlers->push_back(http_method_handler(method, handler));
}
int HttpService::GetRoute(const char* url, http_method method, http_handler** handler) {
// {base_url}/path?query
const char* s = url;
const char* b = base_url.c_str();
while (*s && *b && *s == *b) {++s;++b;}
if (*b != '\0') {
return HTTP_STATUS_NOT_FOUND;
}
const char* e = s;
while (*e && *e != '?') ++e;
std::string path = std::string(s, e);
auto iter = pathHandlers.find(path);
if (iter == pathHandlers.end()) {
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->handler;
return 0;
}
}
if (handler) *handler = NULL;
return HTTP_STATUS_METHOD_NOT_ALLOWED;
}
int HttpService::GetRoute(HttpRequest* req, http_handler** handler) {
// {base_url}/path?query
const char* s = req->path.c_str();
const char* b = base_url.c_str();
while (*s && *b && *s == *b) {++s;++b;}
if (*b != '\0') {
return HTTP_STATUS_NOT_FOUND;
}
const char* e = s;
while (*e && *e != '?') ++e;
std::string path = std::string(s, e);
const char *kp, *ks, *vp, *vs;
bool match;
for (auto iter = pathHandlers.begin(); iter != pathHandlers.end(); ++iter) {
kp = iter->first.c_str();
vp = path.c_str();
match = false;
std::map<std::string, std::string> params;
while (*kp && *vp) {
if (kp[0] == '*') {
// wildcard *
match = hv_strendswith(vp, kp+1);
break;
} else if (*kp != *vp) {
match = false;
break;
} else if (kp[0] == '/' && (kp[1] == ':' || kp[1] == '{')) {
// RESTful /:field/
// RESTful /{field}/
kp += 2;
ks = kp;
while (*kp && *kp != '/') {++kp;}
vp += 1;
vs = vp;
while (*vp && *vp != '/') {++vp;}
int klen = kp - ks;
if (*(ks-1) == '{' && *(kp-1) == '}') {
--klen;
}
params[std::string(ks, klen)] = std::string(vs, vp-vs);
continue;
} else {
++kp;
++vp;
}
}
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[field]
req->query_params[param.first] = param.second;
}
if (handler) *handler = &iter->handler;
return 0;
}
}
if (params.size() == 0) {
if (handler) *handler = NULL;
return HTTP_STATUS_METHOD_NOT_ALLOWED;
}
}
}
if (handler) *handler = NULL;
return HTTP_STATUS_NOT_FOUND;
}
void HttpService::Static(const char* path, const char* dir) {
std::string strPath(path);
if (strPath.back() != '/') strPath += '/';
std::string strDir(dir);
if (strDir.back() == '/') strDir.pop_back();
staticDirs[strPath] = strDir;
}
std::string HttpService::GetStaticFilepath(const char* path) {
std::string filepath;
for (auto iter = staticDirs.begin(); iter != staticDirs.end(); ++iter) {
if (hv_strstartswith(path, iter->first.c_str())) {
filepath = iter->second + (path + iter->first.length() - 1);
break;
}
}
if (filepath.empty()) {
return filepath;
}
if (filepath.back() == '/') {
filepath += home_page;
}
return filepath;
}
void HttpService::Proxy(const char* path, const char* url) {
proxies[path] = url;
}
std::string HttpService::GetProxyUrl(const char* path) {
std::string url;
for (auto iter = proxies.begin(); iter != proxies.end(); ++iter) {
if (hv_strstartswith(path, iter->first.c_str())) {
url = iter->second + (path + iter->first.length());
break;
}
}
return url;
}
void HttpService::AddTrustProxy(const char* host) {
trustProxies.emplace_back(host);
}
void HttpService::AddNoProxy(const char* host) {
noProxies.emplace_back(host);
}
bool HttpService::IsTrustProxy(const char* host) {
if (!host || *host == '\0') return false;
bool trust = true;
if (trustProxies.size() != 0) {
trust = false;
for (const auto& trust_proxy : trustProxies) {
if (hv_wildcard_match(host, trust_proxy.c_str())) {
trust = true;
break;
}
}
}
if (noProxies.size() != 0) {
for (const auto& no_proxy : noProxies) {
if (hv_wildcard_match(host, no_proxy.c_str())) {
trust = false;
break;
}
}
}
return trust;
}
void HttpService::AllowCORS() {
Use(HttpMiddleware::CORS);
}
}