Fix crash on malformed request paths
This commit is contained in:
+7
-2
@@ -2,7 +2,7 @@
|
|||||||
import asyncdispatch, strformat, logging
|
import asyncdispatch, strformat, logging
|
||||||
from net import Port
|
from net import Port
|
||||||
from htmlgen import a
|
from htmlgen import a
|
||||||
from os import getEnv
|
from os import getEnv, normalizedPath
|
||||||
|
|
||||||
import jester
|
import jester
|
||||||
|
|
||||||
@@ -63,12 +63,17 @@ createDebugRouter(cfg)
|
|||||||
|
|
||||||
settings:
|
settings:
|
||||||
port = Port(cfg.port)
|
port = Port(cfg.port)
|
||||||
staticDir = cfg.staticDir
|
staticDir = normalizedPath(cfg.staticDir)
|
||||||
bindAddr = cfg.address
|
bindAddr = cfg.address
|
||||||
reusePort = true
|
reusePort = true
|
||||||
|
maxBody = 64 * 1024
|
||||||
|
|
||||||
routes:
|
routes:
|
||||||
before:
|
before:
|
||||||
|
# Reject malformed paths
|
||||||
|
if request.path.len == 0 or request.path[0] != '/':
|
||||||
|
halt Http400
|
||||||
|
|
||||||
# skip all file URLs
|
# skip all file URLs
|
||||||
cond "." notin request.path
|
cond "." notin request.path
|
||||||
applyUrlPrefs()
|
applyUrlPrefs()
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import subprocess
|
||||||
|
from parameterized import parameterized
|
||||||
|
|
||||||
|
BASE_URL = 'http://localhost:8080'
|
||||||
|
|
||||||
|
|
||||||
|
def curl_status(url):
|
||||||
|
"""Get HTTP status code using curl to avoid URL normalization by Python libs."""
|
||||||
|
result = subprocess.run(
|
||||||
|
['curl', '-s', '-o', '/dev/null', '-w', '%{http_code}', url],
|
||||||
|
capture_output=True, text=True, timeout=10
|
||||||
|
)
|
||||||
|
return int(result.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMalformedPaths:
|
||||||
|
"""Test that malformed paths don't crash the server.
|
||||||
|
|
||||||
|
URLs like //foo are parsed as having 'foo' as the authority (host),
|
||||||
|
resulting in an empty path. Empty paths previously crashed jester's
|
||||||
|
static file handler. Now they return 400.
|
||||||
|
|
||||||
|
URLs like //foo/bar are parsed as authority='foo', path='/bar',
|
||||||
|
so they route normally (not empty path).
|
||||||
|
"""
|
||||||
|
|
||||||
|
@parameterized.expand([
|
||||||
|
# These parse to empty paths -> 400
|
||||||
|
('//lefty_rae', 400),
|
||||||
|
('//test', 400),
|
||||||
|
('//anyuser', 400),
|
||||||
|
])
|
||||||
|
def test_empty_path_returns_400(self, path, expected_status):
|
||||||
|
"""URLs that parse to empty paths should return 400, not crash."""
|
||||||
|
status = curl_status(f'{BASE_URL}{path}')
|
||||||
|
assert status == expected_status, \
|
||||||
|
f'Expected {expected_status} for {path}, got {status}'
|
||||||
|
|
||||||
|
@parameterized.expand([
|
||||||
|
('/jack', 200),
|
||||||
|
('/about', 200),
|
||||||
|
('/', 200),
|
||||||
|
])
|
||||||
|
def test_normal_paths_work(self, path, expected_status):
|
||||||
|
"""Normal paths should still work."""
|
||||||
|
status = curl_status(f'{BASE_URL}{path}')
|
||||||
|
assert status == expected_status, \
|
||||||
|
f'Expected {expected_status} for {path}, got {status}'
|
||||||
|
|
||||||
|
def test_server_survives_malformed_requests(self):
|
||||||
|
"""Server should handle malformed requests without crashing."""
|
||||||
|
# These all parse to empty paths
|
||||||
|
malformed_paths = ['//a', '//b', '//c', '//user', '//test']
|
||||||
|
for path in malformed_paths:
|
||||||
|
status = curl_status(f'{BASE_URL}{path}')
|
||||||
|
assert status == 400, f'Expected 400 for {path}, got {status}'
|
||||||
|
|
||||||
|
# Verify server is still responding after malformed requests
|
||||||
|
status = curl_status(f'{BASE_URL}/')
|
||||||
|
assert status == 200, 'Server should still be alive'
|
||||||
Reference in New Issue
Block a user