diff --git a/include/http_server.h b/include/http_server.h index d75ef8a3..b7b66ec1 100644 --- a/include/http_server.h +++ b/include/http_server.h @@ -42,6 +42,8 @@ private: std::string ssl_cert_key_path; + bool cors_enabled; + bool (*auth_handler)(const route_path & rpath, const std::string & auth_key); static void on_accept(h2o_socket_t *listener, const char *err); @@ -67,7 +69,7 @@ private: public: HttpServer(std::string listen_address, uint32_t listen_port, - std::string ssl_cert_path, std::string ssl_cert_key_path); + std::string ssl_cert_path, std::string ssl_cert_key_path, bool cors_enabled); ~HttpServer(); diff --git a/src/http_server.cpp b/src/http_server.cpp index 6bd9bd46..262ae341 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -26,10 +26,10 @@ struct h2o_custom_generator_t { void* data; }; -HttpServer::HttpServer(std::string listen_address, uint32_t listen_port, - std::string ssl_cert_path, std::string ssl_cert_key_path): - listen_address(listen_address), listen_port(listen_port), - ssl_cert_path(ssl_cert_path), ssl_cert_key_path(ssl_cert_key_path) { +HttpServer::HttpServer(std::string listen_address, uint32_t listen_port, std::string ssl_cert_path, + std::string ssl_cert_key_path, bool cors_enabled): + listen_address(listen_address), listen_port(listen_port), ssl_cert_path(ssl_cert_path), + ssl_cert_key_path(ssl_cert_key_path), cors_enabled(cors_enabled) { accept_ctx = new h2o_accept_ctx_t(); h2o_config_init(&config); hostconf = h2o_config_register_host(&config, h2o_iovec_init(H2O_STRLIT("default")), 65535); @@ -283,6 +283,40 @@ int HttpServer::catch_all_handler(h2o_handler_t *_self, h2o_req_t *req) { auth_key_from_header = query_map[AUTH_HEADER]; } + // Handle OPTIONS for CORS + if(self->http_server->cors_enabled && http_method == "OPTIONS") { + // locate request access control headers + const char* ACL_REQ_HEADERS = "access-control-request-headers"; + ssize_t acl_header_cursor = h2o_find_header_by_str(&req->headers, ACL_REQ_HEADERS, strlen(ACL_REQ_HEADERS), -1); + + if(acl_header_cursor != -1) { + h2o_iovec_t &slot = req->headers.entries[acl_header_cursor].value; + const char* acl_req_headers = std::string(slot.base, slot.len).c_str(); + + h2o_generator_t generator = {NULL, NULL}; + h2o_iovec_t res_body = h2o_strdup(&req->pool, "", SIZE_MAX); + req->res.status = 200; + req->res.reason = get_status_reason(200); + + h2o_add_header_by_str(&req->pool, &req->res.headers, + H2O_STRLIT("Access-Control-Allow-Origin"), + 0, NULL, H2O_STRLIT("*")); + h2o_add_header_by_str(&req->pool, &req->res.headers, + H2O_STRLIT("Access-Control-Allow-Methods"), + 0, NULL, H2O_STRLIT("POST, GET, DELETE, PUT, PATCH, OPTIONS")); + h2o_add_header_by_str(&req->pool, &req->res.headers, + H2O_STRLIT("Access-Control-Allow-Headers"), + 0, NULL, acl_req_headers, strlen(acl_req_headers)); + h2o_add_header_by_str(&req->pool, &req->res.headers, + H2O_STRLIT("Access-Control-Max-Age"), + 0, NULL, H2O_STRLIT("86400")); + + h2o_start_response(req, &generator); + h2o_send(req, &res_body, 1, H2O_SEND_STATE_FINAL); + return 0; + } + } + for(const route_path & rpath: self->http_server->routes) { if(rpath.path_parts.size() != path_parts.size() || rpath.http_method != http_method) { continue; diff --git a/src/main/typesense_server.cpp b/src/main/typesense_server.cpp index 170443ff..7e0ade1f 100644 --- a/src/main/typesense_server.cpp +++ b/src/main/typesense_server.cpp @@ -71,6 +71,8 @@ int main(int argc, char **argv) { options.add("ssl-certificate", 'c', "Path to the SSL certificate file.", false, ""); options.add("ssl-certificate-key", 'e', "Path to the SSL certificate key file.", false, ""); + options.add("enable-cors", '\0', "Enable CORS requests."); + options.parse_check(argc, argv); signal(SIGINT, catch_interrupt); @@ -100,7 +102,8 @@ int main(int argc, char **argv) { options.get("listen-address"), options.get("listen-port"), options.get("ssl-certificate"), - options.get("ssl-certificate-key") + options.get("ssl-certificate-key"), + options.exist("enable-cors") ); server->set_auth_handler(handle_authentication);