1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

fix(http): don't expose body on GET/HEAD requests (#12260)

GET/HEAD requests can't have bodies according to `fetch` spec. This
commit changes the HTTP server to hide request bodies for requests with
GET or HEAD methods.
This commit is contained in:
Luca Casonato 2021-10-11 18:39:55 +02:00 committed by GitHub
parent 70978fd05a
commit c40d5040cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 7 deletions

View file

@ -67,6 +67,40 @@ unitTest({ permissions: { net: true } }, async function httpServerBasic() {
await promise; await promise;
}); });
unitTest(
{ permissions: { net: true } },
async function httpServerGetRequestBody() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
listener.close();
const httpConn = Deno.serveHttp(conn);
const e = await httpConn.nextRequest();
assert(e);
const { request, respondWith } = e;
assertEquals(request.body, null);
await respondWith(new Response("", { headers: {} }));
httpConn.close();
})();
const conn = await Deno.connect({ port: 4501 });
// Send GET request with a body + content-length.
const encoder = new TextEncoder();
const body =
`GET / HTTP/1.1\r\nHost: 127.0.0.1:4501\r\nContent-Length: 5\r\n\r\n12345`;
const writeResult = await conn.write(encoder.encode(body));
assertEquals(body.length, writeResult);
const resp = new Uint8Array(200);
const readResult = await conn.read(resp);
assertEquals(readResult, 115);
conn.close();
await promise;
},
);
unitTest( unitTest(
{ permissions: { net: true } }, { permissions: { net: true } },
async function httpServerStreamResponse() { async function httpServerStreamResponse() {

View file

@ -93,7 +93,12 @@
let body = null; let body = null;
if (typeof requestRid === "number") { if (typeof requestRid === "number") {
SetPrototypeAdd(this.managedResources, requestRid); SetPrototypeAdd(this.managedResources, requestRid);
body = createRequestBodyStream(this, requestRid); // There might be a body, but we don't expose it for GET/HEAD requests.
// It will be closed automatically once the request has been handled and
// the response has been sent.
if (method !== "GET" && method !== "HEAD") {
body = createRequestBodyStream(this, requestRid);
}
} }
const innerRequest = newInnerRequest( const innerRequest = newInnerRequest(

View file

@ -29,6 +29,7 @@ use hyper::http;
use hyper::server::conn::Http; use hyper::server::conn::Http;
use hyper::service::Service as HyperService; use hyper::service::Service as HyperService;
use hyper::Body; use hyper::Body;
use hyper::Method;
use hyper::Request; use hyper::Request;
use hyper::Response; use hyper::Response;
use serde::Deserialize; use serde::Deserialize;
@ -243,13 +244,11 @@ fn prepare_next_request(
let url = req_url(&req, scheme, addr)?; let url = req_url(&req, scheme, addr)?;
let is_websocket = is_websocket_request(&req); let is_websocket = is_websocket_request(&req);
let has_body = if let Some(exact_size) = req.size_hint().exact() { let can_have_body = !matches!(*req.method(), Method::GET | Method::HEAD);
exact_size > 0 let has_body =
} else { is_websocket || (can_have_body && req.size_hint().exact() != Some(0));
true
};
let maybe_request_rid = if is_websocket || has_body { let maybe_request_rid = if has_body {
let request_rid = state.resource_table.add(RequestResource { let request_rid = state.resource_table.add(RequestResource {
conn_rid, conn_rid,
inner: AsyncRefCell::new(RequestOrStreamReader::Request(Some(req))), inner: AsyncRefCell::new(RequestOrStreamReader::Request(Some(req))),