diff --git a/docs/content/exporting/http/_index.md b/docs/content/exporting/http/_index.md index 71edc7e3..dc1b8f2c 100644 --- a/docs/content/exporting/http/_index.md +++ b/docs/content/exporting/http/_index.md @@ -52,4 +52,23 @@ chain is used (see Python [ssl.SSLContext.load_default_certs()](https://docs.pyt from prometheus_client import start_http_server start_http_server(8000, certfile="server.crt", keyfile="server.key") -``` \ No newline at end of file +``` + +# Supported HTTP methods + +The prometheus client will handle the following HTTP methods and resources: + +* `OPTIONS (any)` - returns HTTP status 200 and an 'Allow' header indicating the + allowed methods (OPTIONS, GET) +* `GET (any)` - returns HTTP status 200 and the metrics data +* `GET /favicon.ico` - returns HTTP status 200 and an empty response body. Some + browsers support this to display the returned icon in the browser tab. + +Other HTTP methods than these are rejected with HTTP status 405 "Method Not Allowed" +and an 'Allow' header indicating the allowed methods (OPTIONS, GET). + +Any returned HTTP errors are also displayed in the response body after a hash +sign and with a brief hint. Example: +``` +# HTTP 405 Method Not Allowed: XXX; use OPTIONS or GET +``` diff --git a/prometheus_client/exposition.py b/prometheus_client/exposition.py index 3a47917c..fab139df 100644 --- a/prometheus_client/exposition.py +++ b/prometheus_client/exposition.py @@ -118,12 +118,24 @@ def prometheus_app(environ, start_response): accept_header = environ.get('HTTP_ACCEPT') accept_encoding_header = environ.get('HTTP_ACCEPT_ENCODING') params = parse_qs(environ.get('QUERY_STRING', '')) - if environ['PATH_INFO'] == '/favicon.ico': + method = environ['REQUEST_METHOD'] + + if method == 'OPTIONS': + status = '200 OK' + headers = [('Allow', 'OPTIONS,GET')] + output = b'' + elif method != 'GET': + status = '405 Method Not Allowed' + headers = [('Allow', 'OPTIONS,GET')] + output = '# HTTP {}: {}; use OPTIONS or GET\n'.format(status, method).encode() + elif environ['PATH_INFO'] == '/favicon.ico': # Serve empty response for browsers status = '200 OK' headers = [('', '')] output = b'' else: + # Note: For backwards compatibility, the URI path for GET is not + # constrained to the documented /metrics, but any path is allowed. # Bake output status, headers, output = _bake_output(registry, accept_header, accept_encoding_header, params, disable_compression) # Return output