fix(server): cap /mcp body size (SRV-03)
Add tests for the /mcp body cap and complete the task file. - oversized POST /mcp with declared Content-Length > 8 MiB -> 413 before any body read - oversized chunked POST /mcp -> 413 (counting-stream cut mid-body; rmcp maps body errors to 500, so the middleware sources the status) - normal-size initialize round-trip unchanged - task file: status completed, Summary filled Verified: cargo test (219), cargo test --features mcp --lib (257), cargo test --all-features (269 + integration), clippy default and --all-features (-D warnings), cargo fmt --check.
This commit is contained in:
+27
-16
@@ -738,32 +738,43 @@ mod tests {
|
||||
let _ = ProtocolHandler::handle(&adapter, conn, &auth).await;
|
||||
});
|
||||
|
||||
let mut client = client;
|
||||
client
|
||||
let (mut reader_client, mut writer_client) = tokio::io::split(client);
|
||||
writer_client
|
||||
.write_all(
|
||||
b"POST /mcp HTTP/1.1\r\nHost: localhost\r\nContent-Type: application/json\r\nAccept: application/json, text/event-stream\r\nTransfer-Encoding: chunked\r\nConnection: close\r\n\r\n",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let chunk_size = 64 * 1024;
|
||||
for _ in 0..(MCP_BODY_LIMIT / chunk_size) + 1 {
|
||||
let header = format!("{chunk_size:x}\r\n");
|
||||
client.write_all(header.as_bytes()).await.unwrap();
|
||||
let chunk = vec![b'a'; chunk_size];
|
||||
client.write_all(&chunk).await.unwrap();
|
||||
client.write_all(b"\r\n").await.unwrap();
|
||||
}
|
||||
client.write_all(b"0\r\n\r\n").await.unwrap();
|
||||
let writer = tokio::spawn(async move {
|
||||
let chunk = vec![b'a'; 64 * 1024];
|
||||
let chunk_header = format!("{:x}\r\n", chunk.len());
|
||||
for _ in 0..(MCP_BODY_LIMIT / chunk.len()) + 1 {
|
||||
if writer_client
|
||||
.write_all(chunk_header.as_bytes())
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if writer_client.write_all(&chunk).await.is_err() {
|
||||
return;
|
||||
}
|
||||
if writer_client.write_all(b"\r\n").await.is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let _ = writer_client.write_all(b"0\r\n\r\n").await;
|
||||
});
|
||||
|
||||
let mut response = Vec::new();
|
||||
let _ = tokio::time::timeout(
|
||||
let read = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(10),
|
||||
client.read_to_end(&mut response),
|
||||
reader_client.read_to_end(&mut response),
|
||||
)
|
||||
.await
|
||||
.expect("read timed out")
|
||||
.unwrap();
|
||||
.await;
|
||||
writer.abort();
|
||||
read.expect("read timed out").unwrap();
|
||||
|
||||
let text = String::from_utf8_lossy(&response);
|
||||
assert!(
|
||||
|
||||
Reference in New Issue
Block a user