Skip to content
Lesson 1 of 16

Step 1 of 5 · Reading · ~4 min

Read

Connection & Parsing

The Request Line

Every HTTP request starts with one line of text. After this lesson your program reads the raw bytes a client sent and answers the first question a server must settle: is this a line I will look at, and if not, which status code do I owe the client?

The bytes on the wire

A browser, curl or a load balancer opens a TCP connection and sends this, byte for byte:

47 45 54 20 2f 73 65 61 72 63 68 3f 71 3d 72 65 64 69 73 20 48 54 54 50 2f 31 2e 31 0d 0a
G  E  T  SP /  s  e  a  r  c  h  ?  q  =  r  e  d  i  s  SP H  T  T  P  /  1  .  1  CR LF

Three fields, one space between each, then the two-byte terminator CR LF (0x0d 0x0a, written \r\n). RFC 9112 section 3 gives the grammar:

request-line = method SP request-target SP HTTP-version CRLF
FieldExampleWhat it is
methodGETthe verb. Case-sensitive: get is not GET
request-target/search?q=redisan opaque string for now. Routing gives it meaning later
versionHTTP/1.1the literal HTTP/, a digit, a dot, a digit

Where does the line end?

TCP delivers a stream of bytes, not messages. The only thing that ends the request line is the two bytes CR LF. Two traps live here.

  • Cut the stream at \n alone and every line keeps a stray \r on its end. The version becomes HTTP/1.1\r, which is not equal to HTTP/1.1, and the bug is invisible in a log.
  • Read the input in your language's text mode and the runtime may rewrite \r\n as \n before you see it. A protocol parser reads bytes.

RFC 9112 lets a server tolerate a bare LF. This course does not. Two components that disagree about where a line ends is how request smuggling starts, so a line that is not terminated by CRLF is a 400. A trailing fragment with no CRLF at all is also a 400: the client has not finished its sentence.

Reject first, accept second

Compare what a real server does with these lines:

GET /a HTTP/1.1          fine
GET  /a HTTP/1.1         two spaces: split on SP gives four fields, one empty
get /a HTTP/1.1          lowercase method
GET /a                   two fields, the version is missing
GET /a HTTP/1.1 \r\n     a trailing space makes a fourth field
GET /a HTTP/1.10         the version is digit, dot, digit. Not digit, dot, digits

All five bad lines are 400 Bad Request. Strictness is security: each of them is a place where two parsers can read the same bytes differently.

The contract for this course

Check in this order and report the first rule that fires.

  1. The line ends in CRLF and holds no other CR or LF.
  2. It has exactly three fields separated by single spaces, none empty.
  3. The method is made only of the letters A to Z. The target starts with /, or is exactly * when the method is OPTIONS, and every byte of it is printable ASCII (0x21 to 0x7e). The version has the shape HTTP/d.d. Any failure is 400.
  4. The method is one of GET HEAD POST PUT DELETE OPTIONS PATCH, otherwise 501 Not Implemented: the line is well formed, you just do not do that.
  5. The version is HTTP/1.0 or HTTP/1.1, otherwise 505 HTTP Version Not Supported: HTTP/2.0 is well formed and you do not speak it.

Syntax errors beat semantic ones, so get / HTTP/2.0 is a 400, not a 505. Between the two semantic rules the method is checked first, so BREW / HTTP/2.0 is a 501.

Common mistakes

  • Printing HTTP/1.1\r because you cut the stream at \n. The version check then fails on every valid line.
  • Splitting on runs of whitespace. That quietly accepts GET /a HTTP/1.1 and GET /a HTTP/1.1 , which the contract rejects.
  • Answering 505 for HTTP/1.10 or HTTP/1.x. Those are not versions at all, they are syntax errors, so 400.
  • Checking the version before the method shape, so get / HTTP/2.0 comes back 505 instead of 400.

Your exercise

The starter reads stdin as bytes and cuts it at every CRLF for you. You write the judgement for one line: the three-field split, the shape checks and the order of the verdicts. Keep the most likely mistake in mind: a rule that is right on its own but fires in the wrong order.

Up nextParsing HeadersConnection & Parsing

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…