8000 Reject invalid HTTP methods and resources · prometheus/client_python@0a15d30 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0a15d30

Browse files
committed
Reject invalid HTTP methods and resources
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 /* - returns 200 and an 'Allow' header indicating allowed methods GET / - returns 200 and metrics GET /metrics - returns 200 and metrics GET /favicon.ico - returns 200 and no body (this is no change) Other resources than these on the allowed HTTP methods are rejected with 404 "Resource Not Found". 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 <maiera@de.ibm.com>
1 parent 4535ce0 commit 0a15d30

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

docs/content/exporting/http/_index.md

Lines changed: 24 additions & 1 deletion
  • < 8000 /ul>
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,27 @@ chain is used (see Python [ssl.SSLContext.load_default_certs()](https://docs.pyt
5252
from prometheus_client import start_http_server
5353

5454
start_http_server(8000, certfile="server.crt", keyfile="server.key")
55-
```
55+
```
56+
57+
# Supported HTTP methods
58+
59+
The prometheus client will handle the following HTTP methods and resources:
60+
61+
* `OPTIONS /*` - returns HTTP status 200 and an 'Allow' header indicating the
62+
allowed methods (OPTIONS, GET)
63+
* `GET /` - returns HTTP status 200 and the metrics data
64+
* `GET /metrics` - returns HTTP status 200 and the metrics data
65+
* `GET /favicon.ico` - returns HTTP status 200 and an empty response body. Some
66+
browsers support this to display the returned icon in the browser tab.
67+
68+
Other resources than these on the allowed OPTIONS and GET methods are rejected
69+
with HTTP status 404 "Resource Not Found".
70+
71+
Other HTTP methods than these are rejected with HTTP status 405 "Method Not Allowed"
72+
and an 'Allow' header indicating the allowed methods (OPTIONS, GET).
73+
74+
Any returned HTTP errors are also displayed in the response body after a hash
75+
sign and with a brief hint. Example:
76+
```
77+
# HTTP 405 Method Not Allowed: XXX; use OPTIONS or GET
78+
```

prometheus_client/exposition.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,29 @@ def prometheus_app(environ, start_response):
118118
accept_header = environ.get('HTTP_ACCEPT')
119119
accept_encoding_header = environ.get('HTTP_ACCEPT_ENCODING')
120120
params = parse_qs(environ.get('QUERY_STRING', ''))
121-
if environ['PATH_INFO'] == '/favicon.ico':
121+
122+
if environ['REQUEST_METHOD'] == 'OPTIONS':
123+
if environ['PATH_INFO'] == '/*':
124+
status = '200 OK'
125+
headers = [('Allow', 'OPTIONS,GET')]
126+
output = b''
127+
else:
128+
status = '404 Resource not found: '
129+
headers = [('', '')]
130+
output = '# HTTP {}: {}; use /*\n'.format(status, environ['PATH_INFO']).encode()
131+
elif environ['REQUEST_METHOD'] != 'GET':
132+
status = '405 Method Not Allowed'
133+
headers = [('Allow', 'OPTIONS,GET')]
134+
output = '# HTTP {}: {}; use OPTIONS or GET\n'.format(status, environ['REQUEST_METHOD']).encode()
135+
elif environ['PATH_INFO'] == '/favicon.ico':
122136
# Serve empty response for browsers
123137
status = '200 OK'
124138
headers = [('', '')]
125139
output = b''
140+
elif environ['PATH_INFO'].strip('/') not in ('', 'metrics'):
141+
status = '404 Resource not found'
142+
headers = [('', '')]
143+
output = '# HTTP {}: {}; use / or /metrics\n'.format(status, environ['PATH_INFO']).encode()
126144
else:
127145
# Bake output
128146
status, headers, output = _bake_output(registry, accept_header, accept_encoding_header, params, disable_compression)

tox.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ deps =
77
pytest
88
attrs
99
{py3.8,pypy3.8}: twisted
10-
py3.8: asgiref
11-
# See https://github.com/django/asgiref/issues/393 for why we need to pin asgiref for pypy
10+
# See https://github.com/django/asgiref/issues/393 for why we need to pin asgiref
11+
py3.8: asgiref==3.6.0
1212
pypy3.8: asgiref==3.6.0
1313
commands = coverage run --parallel -m pytest {posargs}
1414

0 commit comments

Comments
 (0)
0