From 7f7481be380942f00178178df1577c71e8be86f8 Mon Sep 17 00:00:00 2001 From: Aki Tuomi Date: Fri, 30 Jan 2015 10:41:41 +0200 Subject: [PATCH] Implement CORS in WebServer, fixes #1984 --- pdns/webserver.cc | 25 ++++++++++++++++++++++++- regression-tests.api/test_Basics.py | 11 +++++++++++ regression-tests.api/test_helper.py | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/pdns/webserver.cc b/pdns/webserver.cc index 4c012cf01..d4bfdedb3 100644 --- a/pdns/webserver.cc +++ b/pdns/webserver.cc @@ -96,8 +96,27 @@ void WebServer::registerBareHandler(const string& url, HandlerFunction handler) YaHTTP::Router::Any(url, f); } +static bool optionsHandler(HttpRequest* req, HttpResponse* resp) { + if (req->method == "OPTIONS") { + resp->headers["access-control-allow-origin"] = "*"; + resp->headers["access-control-allow-headers"] = "Content-Type, X-API-Key"; + resp->headers["access-control-allow-methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"; + resp->headers["access-control-max-age"] = "3600"; + resp->status = 200; + resp->headers["content-type"]= "text/plain"; + resp->body = ""; + return true; + } + return false; +} + static void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) { const string& api_key = arg()["experimental-api-key"]; + + if (optionsHandler(req, resp)) return; + + resp->headers["access-control-allow-origin"] = "*"; + if (api_key.empty()) { L<url.path << "\": Authentication failed, API Key missing in config" << endl; throw HttpUnauthorizedException(); @@ -109,7 +128,6 @@ static void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, Htt throw HttpBadRequestException(); } - resp->headers["Access-Control-Allow-Origin"] = "*"; resp->headers["Content-Type"] = "application/json"; string callback; @@ -151,6 +169,11 @@ void WebServer::registerApiHandler(const string& url, HandlerFunction handler) { static void webWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) { const string& web_password = arg()["webserver-password"]; + + if (optionsHandler(req, resp)) return; + + resp->headers["access-control-allow-origin"] = "*"; + if (!web_password.empty()) { bool auth_ok = req->compareAuthorization(web_password); if (!auth_ok) { diff --git a/regression-tests.api/test_Basics.py b/regression-tests.api/test_Basics.py index 1856e41e5..c275018e5 100644 --- a/regression-tests.api/test_Basics.py +++ b/regression-tests.api/test_Basics.py @@ -31,3 +31,14 @@ class TestBasics(ApiTestCase): status = resp.splitlines(0)[0] if '400' in status: raise Exception('Got unwanted response: %s' % status) + + def test_cors(self): + r = self.session.options(self.url("/servers/localhost")) + # look for CORS headers + + self.assertEquals(r.status_code, requests.codes.ok) + self.assertEquals(r.headers['access-control-allow-origin'], "*") + self.assertEquals(r.headers['access-control-allow-headers'], 'Content-Type, X-API-Key') + self.assertEquals(r.headers['access-control-allow-methods'], 'GET, POST, PUT, PATCH, DELETE, OPTIONS') + + print "response", repr(r.headers) diff --git a/regression-tests.api/test_helper.py b/regression-tests.api/test_helper.py index 448b2b61c..494b3be0e 100644 --- a/regression-tests.api/test_helper.py +++ b/regression-tests.api/test_helper.py @@ -15,7 +15,7 @@ class ApiTestCase(unittest.TestCase): self.server_port = int(os.environ.get('WEBPORT', '5580')) self.server_url = 'http://%s:%s/' % (self.server_address, self.server_port) self.session = requests.Session() - self.session.headers = {'X-API-Key': os.environ.get('APIKEY', 'changeme-key')} + self.session.headers = {'X-API-Key': os.environ.get('APIKEY', 'changeme-key'), 'Origin': 'http://%s:%s' % (self.server_address, self.server_port)} def url(self, relative_url): return urlparse.urljoin(self.server_url, relative_url) -- 2.40.0