Skip to content

Commit

Permalink
Reject invalid HTTP methods and resources
Browse files Browse the repository at this point in the history
This change addresses the issue that currently, any HTTP method is handled
by returning success and metrics data, which causes network scanners to
report issues.

Details:

* This change rejects any HTTP methods and resources other than the following:

    OPTIONS (any) - returns 200 and an 'Allow' header indicating allowed methods
    GET (any) - returns 200 and metrics
    GET /favicon.ico - returns 200 and no body (this is no change)

  Other HTTP methods than these are rejected with 405 "Method Not Allowed"
  and an 'Allow' header indicating the allowed HTTP methods.

  Any returned HTTP errors are also displayed in the response body after a
  hash sign and with a brief hint,
  e.g. "# HTTP 405 Method Not Allowed: XXX; use OPTIONS or GET".

* Needed to pin asgiref to ==3.6.0 also for py3.8 to circumvent
  the same error as for pypy3.8.

Signed-off-by: Andreas Maier <[email protected]>
  • Loading branch information
andy-maier committed Jul 29, 2024
1 parent 09a5ae3 commit 5ae9852
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 4 deletions.
21 changes: 20 additions & 1 deletion docs/content/exporting/http/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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")
```
```

# 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
```
13 changes: 12 additions & 1 deletion prometheus_client/exposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,23 @@ 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':

if environ['REQUEST_METHOD'] == 'OPTIONS':
status = '200 OK'
headers = [('Allow', 'OPTIONS,GET')]
output = b''
elif environ['REQUEST_METHOD'] != 'GET':
status = '405 Method Not Allowed'
headers = [('Allow', 'OPTIONS,GET')]
output = '# HTTP {}: {}; use OPTIONS or GET\n'.format(status, environ['REQUEST_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
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ deps =
pytest
attrs
{py3.8,pypy3.8}: twisted
py3.8: asgiref
# See https://github.com/django/asgiref/issues/393 for why we need to pin asgiref for pypy
# See https://github.com/django/asgiref/issues/393 for why we need to pin asgiref
py3.8: asgiref==3.6.0
pypy3.8: asgiref==3.6.0
commands = coverage run --parallel -m pytest {posargs}

Expand Down

0 comments on commit 5ae9852

Please sign in to comment.