Skip to content

Commit 929ebca

Browse files
author
Krish
committed
minor changes to tls mock server
1 parent e6f56c4 commit 929ebca

File tree

2 files changed

+99
-20
lines changed

2 files changed

+99
-20
lines changed

tests/mock_server/README.md

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,46 @@ Python 3.5+ required.
1414
* Have the cert/key ready. The script now using `../resources/unittests.crt`, you can either just run the script within this directory, which will find the certificates and key from the related path, or you can use your own and change the code coordinately.
1515
* Run python. `python3 ./server.py`.
1616

17-
#### Echo
17+
#### Endpoints
1818

19-
* Minor changed based on the example to response the headers of requests back within the headers from `/echo`.
20-
* To test the server runs correctly, you can do `curl -k -v -H "foo:bar" https://localhost:3443/echo` and check the result.
19+
##### `/echo` - Echo endpoint (default)
2120

22-
#### Download test
21+
Echoes back request headers and body as JSON.
2322

24-
* To test download, when `:path` is `/downloadTest`, server will response a repeated string with length `self.download_test_length`, which is 2,500,000,000 now. It will be repeats of sting "This is CRT HTTP test."
25-
* To test the server runs correctly, you can do `curl -k -v -H "foo:bar" https://localhost:3443/downloadTest` and check the result.
23+
```bash
24+
curl -k -v -H "foo:bar" https://localhost:3443/echo
25+
```
2626

27-
#### Slow Connection Test
27+
##### `/echo` with `x-repeat-data` header - Download test
2828

29-
* Simulate a slow connection when `:path` is `/slowConnTest`. The speed is controlled by `out_bytes_per_second`. Default speed is 900 B/s, which will send 900 bytes of data and wait a sec to send new 900 bytes of data.
29+
Sends repeated test pattern of specified size (in bytes).
3030

31-
#### Upload test
31+
```bash
32+
# Download 1MB of repeated data
33+
curl -k -v -H "x-repeat-data: 1000000" https://localhost:3443/echo
34+
```
3235

33-
* To test upload, when `:method` is `POST` or `PUT`, server will response the length received from response body
34-
* To test the server runs correctly, you can do `curl -k -X POST -F'data=@upload_test.txt' https://localhost:3443/upload_test` where `upload_test.txt` is file to upload.
36+
##### `/echo` with `x-repeat-data` + `x-slow-response` headers - Slow connection test
37+
38+
Sends repeated data throttled to ~900 bytes/sec (for timeout testing).
39+
40+
```bash
41+
# Download 5MB slowly at default speed (900 bytes/sec)
42+
curl -k -v -H "x-repeat-data: 5000000" -H "x-slow-response: true" https://localhost:3443/echo
43+
```
44+
45+
##### `/echo` with custom throughput - Custom speed test
46+
47+
Override default throughput with `x-throughput-bps` header.
48+
49+
```bash
50+
# Download 5MB at 500 bytes/sec
51+
curl -k -v -H "x-repeat-data: 5000000" -H "x-slow-response: true" -H "x-throughput-bps: 500" https://localhost:3443/echo
52+
```
3553

36-
#### expect500
54+
##### Any other path
3755

38-
* The server will always return `500` for `:status`, when the `:path` is `/expect500`
56+
Returns 404 Not Found.
3957

4058
### Non-TLS server
4159

tests/mock_server/h2tls_mock_server.py

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,22 @@
88
99
A fully-functional HTTP/2 server using asyncio. Requires Python 3.5+.
1010
11-
This example demonstrates handling requests with bodies, as well as handling
12-
those without. In particular, it demonstrates the fact that DataReceived may
13-
be called multiple times, and that applications must handle that possibility.
11+
Supported endpoints:
12+
13+
1. GET /echo (default)
14+
- Echoes back request headers and body as JSON
15+
16+
2. GET /echo with x-repeat-data header
17+
- x-repeat-data: <bytes> - Sends repeated test pattern of specified size
18+
- Example: x-repeat-data: 1000000 (sends 1MB)
19+
20+
3. GET /echo with x-repeat-data + x-slow-response headers
21+
- x-slow-response: true - Throttles response to ~900 bytes/sec (for timeout testing)
22+
- x-throughput-bps: <number> - Optional: Override throughput (default 900)
23+
- Example: x-repeat-data: 5000000, x-slow-response: true, x-throughput-bps: 500
24+
25+
4. Any other path
26+
- Returns 404 Not Found
1427
"""
1528
import asyncio
1629
import io
@@ -100,6 +113,47 @@ def request_received(self, headers: List[Tuple[str, str]], stream_id: int):
100113
self.stream_data[stream_id] = request_data
101114

102115
def handle_request_echo(self, stream_id: int, request_data: RequestData):
116+
"""
117+
Handle /echo endpoint with optional special headers:
118+
- x-repeat-data: <bytes> - Triggers send_repeat_data() with specified length
119+
- x-slow-response: true - Triggers send_slow_repeat_data() instead (requires x-repeat-data)
120+
- x-throughput-bps: <number> - Override throughput for slow response (default 900)
121+
122+
Without special headers, echoes request headers and body as JSON.
123+
"""
124+
headers_dict = dict(self.raw_headers)
125+
126+
# Check for x-repeat-data header
127+
repeat_data_header = headers_dict.get('x-repeat-data')
128+
if repeat_data_header:
129+
try:
130+
length = int(repeat_data_header)
131+
response_headers = [(':status', '200')]
132+
self.conn.send_headers(stream_id, response_headers, end_stream=False)
133+
134+
# Check for slow response
135+
if headers_dict.get('x-slow-response') == 'true':
136+
# Check for custom throughput
137+
throughput_header = headers_dict.get('x-throughput-bps')
138+
if throughput_header:
139+
self.out_bytes_per_second = int(throughput_header)
140+
asyncio.ensure_future(self.send_slow_repeat_data(length, stream_id))
141+
else:
142+
asyncio.ensure_future(self.send_repeat_data(length, stream_id))
143+
return
144+
except ValueError:
145+
pass # Fall through to echo behavior
146+
147+
# Check for upload test (don't echo body, just return byte count)
148+
if headers_dict.get('x-upload-test') == 'true':
149+
body_bytes = request_data.data.getvalue()
150+
data = json.dumps({"bytes": len(body_bytes)}, indent=4).encode("utf8")
151+
response_headers = [(':status', '200'), ('content-length', str(len(data)))]
152+
self.conn.send_headers(stream_id, response_headers, end_stream=False)
153+
asyncio.ensure_future(self.send_data(data, stream_id))
154+
return
155+
156+
# Default echo behavior
103157
response_headers = [(':status', '200')]
104158
# Filter out headers that shouldn't be echoed back
105159
skip_headers = {'content-length', 'content-encoding', 'transfer-encoding'}
@@ -108,9 +162,12 @@ def handle_request_echo(self, stream_id: int, request_data: RequestData):
108162
if i[0][0] != ':' and i[0].lower() not in skip_headers:
109163
response_headers.append(i)
110164

111-
body = request_data.data.getvalue().decode('utf-8')
165+
body_bytes = request_data.data.getvalue()
166+
167+
body = body_bytes.decode('utf-8')
168+
112169
data = json.dumps(
113-
{"body": body}, indent=4
170+
{"body": body, "bytes": len(body_bytes)}, indent=4,
114171
).encode("utf8")
115172

116173
# Add correct content-length for our response
@@ -198,7 +255,9 @@ async def send_data(self, data, stream_id):
198255

199256
async def send_repeat_data(self, length, stream_id):
200257
"""
201-
Send data with length according to the flow control rules.
258+
Send repeated test pattern data of specified length.
259+
Respects HTTP/2 flow control rules.
260+
Triggered by x-repeat-data header on /echo endpoint.
202261
"""
203262
while length > 0:
204263
while self.conn.local_flow_control_window(stream_id) < 1:
@@ -232,7 +291,9 @@ async def send_repeat_data(self, length, stream_id):
232291

233292
async def send_slow_repeat_data(self, length, stream_id):
234293
"""
235-
Send data with length slowly (less than 1000 bytes per second)
294+
Send repeated test pattern data slowly (throttled to out_bytes_per_second, default 900).
295+
Used for timeout and slow connection testing.
296+
Triggered by x-repeat-data + x-slow-response headers on /echo endpoint.
236297
"""
237298
while length > 0:
238299
while self.conn.local_flow_control_window(stream_id) < 1:

0 commit comments

Comments
 (0)