The Shape of a Request
Every HTTP request has three main parts:
- The Request Line
- The Headers
- (Sometimes) The Body
HTTP Requests start with the Request Line:
It tells the server what you want to do (e.g. GET
, POST
, DELETE
) and where you want to do it.
GET /login HTTP/1.1
Then Headers, one per line:
These provide extra context about the request in a key: value
format.
GET /login HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
In this example, you're telling the server:
- Which domain you're asking for (
Host
) - What kind of client you are (
User-Agent
) - What response format you can handle (
Accept
)
It's worth noting that nothing prevents you from adding your own custom headers and using them in your applications! Once again, they're just text with a contextual meaning.
X-Forwarded-For
, X-Real-IP
, or X-Framework-Version
can expose internal network topology, load balancers, or tech stack details that attackers may use for reconnaissance.
An empty line separates Headers from the (optional) Body:
That blank line is important. It's how the server knows, "Okay, headers are done, now here's the payload." It's so important that even if there's no body, you still need to include the blank line.
GET /login HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
The Body (optional):
The body is your payload. Everything else is preamble.
Used in requests with POST
, PUT
, or PATCH
when you're sending data.
Let's turn our example into a POST
request and give it a body:
POST /login HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=admin&password=letmein
Body Type Examples
- Form data (what login forms typically send):
username=admin&password=secret123
- JSON (what modern web apps prefer):
{"username": "admin", "password": "secret123"}
- Plain text (sometimes used for simple API calls):
Hello, server! Please process this message.
Different body types require different Content-Type
headers. The server needs to know how to interpret what you're sending.
Whitespace Matters
Line breaks, indentation, even an extra space in the wrong spot can break things.
It's not quite poetry, but the formatting does have rhythm.
Headers Are Like Social Cues
They shape how the server “perceives” the client. Are you a browser? A bot? Are you already logged in?
The server trusts your headers at face value, so spoofing or manipulating them is like donning a disguise. Understanding these cues will also be crucial to learning to lie convincingly in your HTTP dialogues.
The Shape of a Response
Responses look a lot like requests - same basic structure, headed in a different direction.
They come from the server, and they tell you things like:
- Whether your request succeeded
- What kind of content is coming back
- Whether you're getting cookies, being redirected, or just being told to go away
Everything you're learning here applies to both HTTP and HTTPS.
The S just means the conversation is encrypted in transit, so nobody else can eavesdrop. But the structure, the verbs, the headers, the claims? All the same. HTTPS is HTTP wearing a trenchcoat and whispering.
Responses start with the Status Line:
HTTP/1.1 200 OK
The status line sets the server's mood: did it reply calmly (200
), redirect nervously (302
), or snap angrily (403
)? We'll get deeper into these shortly.
Then come the Response Headers:
These may describe what's coming in the body, how the browser should handle it, and other instructions for future requests:
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: session=abc123; HttpOnly
Content-Type
tells the browser: “This is HTML - render it.”Set-Cookie
gives the client a cookie to send back with the subsequent requests (in theCookie
header).
JSON
but receives XML
? Or when Content-Type
says "image" but the body contains JavaScript? These mismatches can bypass security controls - we'll explore this in depth later.
An empty line, then the Body (if any):
This is where the real content lives - HTML, CSS, JavaScript, JSON, images, etc. These are the things that actually end up being rendered in your browser window.
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: session=abc123; HttpOnly
<html>
<body>
<h1>Welcome back!</h1>
</body>
</html>
We'll come back to this later, but just know: servers leak. They leak secrets in headers, error messages, HTML comments, script tags, response headers. Learning to read responses like a spy will pay off later.
Request Headers ≠ Response Headers
- You might send a
Cookie
in the request. - The server replies with
Set-Cookie
. - You might send
Accept: application/json
- The server replies with
Content-Type: application/json
This is a two-way conversation. The client asks, the server answers.
Status Codes and Semantics
HTTP response status codes aren't just numbers, they're like emotions the server communicates back to you.
Think of them like facial expressions or tone of voice. They're quick signals that shape the rest of the conversation. Or think of them like body language, because they'll tell you instantly whether something is wrong!
Status codes grouped by vibe:
- 1xx – “I'm thinking…” (rarely seen by most people)
- 2xx – “Sure thing!” (everything went fine)
- 3xx – “Look over there instead” (redirects)
- 4xx – “You messed up” (client error)
- 5xx – “I messed up” (server error)
Examples - 200 OK - "Everything worked perfectly". The golden standard - your request succeeded and you got what you asked for. - 404 Not Found - "That page doesn't exist" But here's a security twist: sometimes servers lie! A 404 might mean "it exists but you can't see it". - 403 Forbidden - "I have what you want, but you can't see it". - 401 Unauthorized - "Who are you? Please log in first"
403
when they should return 401
. This tiny difference leaks information - a 403
tells an attacker "this exists, you just don't have permission".