diff --git a/jtlsrv-cpp/src/http.cpp b/jtlsrv-cpp/src/http.cpp index e37a40e..7896861 100644 --- a/jtlsrv-cpp/src/http.cpp +++ b/jtlsrv-cpp/src/http.cpp @@ -70,6 +70,12 @@ int64_t HttpRequest::get_query_int64(const std::string& key, int64_t def) const // HttpResponse // --------------------------------------------------------------------------- +static const char* CORS_HEADERS = + "Access-Control-Allow-Origin: *\r\n" + "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n" + "Access-Control-Allow-Headers: Content-Type, Authorization\r\n" + "Access-Control-Max-Age: 86400\r\n"; + void HttpResponse::send_json(int code, const json& body) { if (headers_sent) return; status_code = code; @@ -80,6 +86,7 @@ void HttpResponse::send_json(int code, const json& body) { "Content-Type: application/json; charset=utf-8\r\n" "Content-Length: " + std::to_string(body_str.size()) + "\r\n" "Connection: keep-alive\r\n" + + std::string(CORS_HEADERS) + "\r\n" + body_str; @@ -95,6 +102,7 @@ void HttpResponse::send_binary(int code, const std::vector& data, const "Content-Type: " + content_type + "\r\n" "Content-Length: " + std::to_string(data.size()) + "\r\n" "Connection: keep-alive\r\n" + + std::string(CORS_HEADERS) + "\r\n"; session_write_binary(session, header, data); @@ -108,6 +116,7 @@ void HttpResponse::send_empty(int code) { std::string resp = "HTTP/1.1 " + std::to_string(code) + " " + reason_phrase(code) + "\r\n" "Content-Length: 0\r\n" "Connection: keep-alive\r\n" + + std::string(CORS_HEADERS) + "\r\n"; session_write(session, resp); diff --git a/jtlsrv-cpp/src/router.cpp b/jtlsrv-cpp/src/router.cpp index d75634c..e8725ab 100644 --- a/jtlsrv-cpp/src/router.cpp +++ b/jtlsrv-cpp/src/router.cpp @@ -18,6 +18,11 @@ void Router::dispatch(tls_session* sess, PairingStore& pairing, const json& conf full_url += "?" + req.query_string; } + if (req.method == "OPTIONS") { + resp.send_empty(204); + return; + } + std::string route_key = req.method + " " + req.path; auto it = routes_.find(route_key); if (it != routes_.end()) { diff --git a/src/http.js b/src/http.js index ee427cc..42cf203 100644 --- a/src/http.js +++ b/src/http.js @@ -13,11 +13,19 @@ export function readBody(req) { }); } +const CORS_HEADERS = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + 'Access-Control-Max-Age': '86400', +}; + export function sendJson(res, statusCode, body) { const responseBody = JSON.stringify(body); res.writeHead(statusCode, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': Buffer.byteLength(responseBody), + ...CORS_HEADERS, }); res.end(responseBody); } @@ -26,10 +34,19 @@ export function sendBinary(res, statusCode, buffer, contentType) { res.writeHead(statusCode, { 'Content-Type': contentType, 'Content-Length': buffer.length, + ...CORS_HEADERS, }); res.end(buffer); } +export function sendCorsPreflight(res) { + res.writeHead(204, { + 'Content-Length': 0, + ...CORS_HEADERS, + }); + res.end(); +} + export function normalizePath(pathname) { return pathname.replace(/^\/api(?=\/v1\/)/, ''); } diff --git a/src/jtl-server.js b/src/jtl-server.js index 3116bae..7f14710 100644 --- a/src/jtl-server.js +++ b/src/jtl-server.js @@ -1,5 +1,5 @@ import { endpoints } from './endpoints/index.js'; -import { normalizePath, readBody, sendJson } from './http.js'; +import { normalizePath, readBody, sendCorsPreflight, sendJson } from './http.js'; function buildConfig(config = {}) { return { @@ -18,6 +18,10 @@ export function createJtlPosServer(pairingStore, config = {}) { const routes = new Map(endpoints.map((endpoint) => [`${endpoint.method} ${endpoint.path}`, endpoint])); async function handle(req, res) { + if (req.method === 'OPTIONS') { + return sendCorsPreflight(res); + } + const url = new URL(req.url, 'https://localhost'); const pathname = normalizePath(url.pathname); const routeKey = `${req.method} ${pathname}`;