deno_std: Error "Cannot read property 'w' of null at iterateHttpRequests" on aborted connections

// server.ts
import { serve } from "https://deno.land/std/http/server.ts";

async function main() {
  for await (let req of serve(":80")) {
    req.respond({});
  }
}

main();
$ deno run --allow-net server.ts
/Users/<redacted>/Library/Caches/deno/deps/https/raw.githubusercontent.com/denoland/deno_std/master/http/server.ts:225:36
            await writeResponse(req.w, {
                                    ^
Uncaught TypeError: Cannot read property 'w' of null
    at iterateHttpRequests (file:///Users/<redacted>/Library/Caches/deno/deps/https/raw.githubusercontent.com/denoland/deno_std/master/http/server.ts:254:31)
$ autocannon localhost
Running 10s test @ localhost
10 connections

┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬──────────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max      │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼──────────┤
│ Latency │ 0 ms │ 0 ms │ 1 ms  │ 2 ms │ 0.07 ms │ 0.39 ms │ 11.05 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴──────────┘
┌───────────┬────────┬────────┬─────────┬─────────┬──────────┬─────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min    │
├───────────┼────────┼────────┼─────────┼─────────┼──────────┼─────────┼────────┤
│ Req/Sec   │ 22879  │ 22879  │ 27695   │ 28287   │ 27145.46 │ 1494.03 │ 22871  │
├───────────┼────────┼────────┼─────────┼─────────┼──────────┼─────────┼────────┤
│ Bytes/Sec │ 869 kB │ 869 kB │ 1.05 MB │ 1.08 MB │ 1.03 MB  │ 56.8 kB │ 869 kB │
└───────────┴────────┴────────┴─────────┴─────────┴──────────┴─────────┴────────┘

Req/Bytes counts sampled once per second.

299k requests in 11.06s, 11.3 MB read

When I restarted the server and ran another load test, it crashed again. Might not be related to the high load, though.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 16 (16 by maintainers)

Most upvoted comments

On a side note, having the HTTP server in the std lib makes it surprisingly easy to debug. ❤️

Here’s a reliable reproduction:

// main.ts
// Run with `deno run --allow-net main.ts`

import { serve } from "https://deno.land/std/http/server.ts";

async function main() {
  for await (let req of serve(":80")) {
    req.respond({});
  }
}

main();
// repro.js
// Run with `node repro.js`

let net = require("net");

let client = net.createConnection({ port: 80 }, () => {
  client.write("GET / HTTP/1.0\r\n\r\n");
  client._destroy(new Error(), _ => {});
});

Cloned deno_std and added a good old console log…

 if (bufStateErr instanceof Error) {
   // An error was thrown while parsing request headers.
+  console.error(bufStateErr);  
   await writeResponse(req.w, {
     status: 400,
     body: new TextEncoder().encode(`${bufStateErr.message}\r\n\r\n`)
   });
 }
❯ make
deno run --allow-net main.ts
[1/1] Compiling file:///Users/marktiedemann/dev/deno_std/http/server.ts
Error: read error
    at read (gen/cli/bundle/main.js:7036:17)
    at async BufReader._fill (/Users/marktiedemann/dev/deno_std/io/bufio.ts:53:22)
    at async BufReader.readSlice (/Users/marktiedemann/dev/deno_std/io/bufio.ts:272:13)
    at async BufReader.readLine (/Users/marktiedemann/dev/deno_std/io/bufio.ts:209:27)
    at async TextProtoReader.readLineSlice (/Users/marktiedemann/dev/deno_std/textproto/mod.ts:121:34)
    at async TextProtoReader.readLine (/Users/marktiedemann/dev/deno_std/textproto/mod.ts:40:27)
    at async readRequest (/Users/marktiedemann/dev/deno_std/http/server.ts:201:24)
    at async Server.iterateHttpRequests (/Users/marktiedemann/dev/deno_std/http/server.ts:231:38)
    at async Server.acceptConnAndIterateHttpRequests (/Users/marktiedemann/dev/deno_std/http/server.ts:276:9)
    at async MuxAsyncIterator.callIteratorNext (/Users/marktiedemann/dev/deno_std/util/async.ts:33:33)
/Users/marktiedemann/dev/deno_std/http/server.ts:250:36
            await writeResponse(req.w, {
                                    ^
Uncaught TypeError: Cannot read property 'w' of null
    at iterateHttpRequests (file:///Users/marktiedemann/dev/deno_std/http/server.ts:279:31)
make: *** [Makefile:3: all] Error 1

The req variable which is null comes from [req, bufStateErr] = await readRequest(bufr);. In readRequest there’s an if (err) { return [null, err]; } block. So in this case, it is guaranteed that, if there is an err in readRequest, the req is null. The err from readRequest in this case is for the case that the HTTP status line can’t be read, I assume because the underlying connection has been closed.

Not sure how to continue with this. Hope my investigation so far is helpful.