
May 19, 2026
Most Ruby developers use HTTP every day.
Whether through:
- Rails API integrations
- webhooks
- OAuth providers
- payment gateways
- microservices
- REST clients
…underneath the stack, many requests still pass through Ruby’s classic net/http.
But few developers ever explore how it actually works internally.
Inside Ruby’s standard library lives a surprisingly sophisticated networking engine featuring:
- socket abstractions
- request serialization
- response parsing
- persistent connections
- SSL/TLS support
- streaming IO
- protocol modeling
In this article we’ll explore the architecture behind Ruby’s HTTP stack by reading the internals of:
- net/http.rb
- net/protocol.rb
- generic_request.rb
- response.rb
- header.rb
- https.rb
The Structure of Ruby’s HTTP Stack
The archive contains the core implementation of Ruby’s networking libraries:
net/├── http.rb├── https.rb├── protocol.rb└── http/ ├── generic_request.rb ├── request.rb ├── response.rb ├── responses.rb ├── requests.rb ├── header.rb ├── status.rb └── exceptions.rb
This is not just helper code.
This is Ruby’s actual HTTP client implementation.
The Request Lifecycle
A simple request:
require 'net/http'uri = URI('https://example.com')response = Net::HTTP.get_response(uri)puts response.codeputs response.body
Looks trivial from the outside.
Internally Ruby performs:
URI ↓TCP Socket ↓SSL Wrapping ↓HTTP Serialization ↓Socket Write ↓Socket Read ↓Header Parsing ↓Response Object Creation ↓Body Streaming
The stdlib implements the entire pipeline manually.
net/protocol.rb — The Hidden Core
One of the most important files is:
net/protocol.rb
This file abstracts:
- buffered IO
- socket communication
- reading/writing
- timeouts
- protocol errors
It acts as the transport foundation for higher-level protocols.
Buffered Reading
Ruby wraps sockets using buffered IO classes.
Simplified concept:
class BufferedIO def readuntil(terminator) # read socket incrementally endend
Why?
Because network communication is:
- partial
- fragmented
- asynchronous
TCP packets do not guarantee complete reads.
Ruby must reconstruct the HTTP protocol stream manually.
Timeout Handling
net/protocol.rb also manages:
open_timeoutread_timeoutwrite_timeout
Example:
http = Net::HTTP.new('example.com')http.open_timeout = 5http.read_timeout = 10
Internally this protects the process from:
- hanging sockets
- dead connections
- stalled servers
This becomes critical in production systems.
How Ruby Builds HTTP Requests
The file:
net/http/generic_request.rb
handles serialization of requests into raw HTTP.
Example: HTTP Request Serialization
Ruby transforms:
Net::HTTP::Get.new('/users')
into:
GET /users HTTP/1.1Host: example.comConnection: closeAccept: */*
Internally the library manually constructs the protocol text.
Core responsibilities include:
- headers
- body encoding
- chunked transfer encoding
- content-length calculation
Important Request Functions
Some of the most relevant methods inside the request system:

HTTP Verbs as Classes
Ruby models HTTP verbs using subclasses.
Examples:
Net::HTTP::GetNet::HTTP::PostNet::HTTP::PutNet::HTTP::Delete
Internally:
class Net::HTTP::Get < Net::HTTPRequestend
This is classic Ruby stdlib OOP design.
Each verb contains protocol semantics.
Response Parsing
Responses are handled in:
net/http/response.rb
Ruby parses:
- status line
- headers
- body
- transfer encoding
- chunked streams
Example Response
Raw HTTP:
HTTP/1.1 200 OKContent-Type: application/jsonContent-Length: 15{"status":"ok"}
Ruby converts this into:
response.code# => "200"response.message# => "OK"response.body# => "{\"status\":\"ok\"}"
HTTP Status Codes as Classes
One of the most elegant parts of the design lives in:
responses.rb
Ruby represents statuses as objects:
Net::HTTPOKNet::HTTPNotFoundNet::HTTPForbiddenNet::HTTPMovedPermanently
This allows:
case responsewhen Net::HTTPSuccess puts "success"when Net::HTTPRedirection puts "redirect"when Net::HTTPClientError puts "client error"end
This is a beautiful example of protocol modeling through inheritance.
Important Response Functions
Key internal functions include:

Header Management
Headers are implemented in:
header.rb
Ruby treats headers as normalized collections.
Example:
response['content-type']
Internally:
- keys are normalized
- duplicate headers are merged
- casing is abstracted away
This simplifies protocol handling dramatically.
Persistent Connections
One of the most important optimizations:
Net::HTTP.start(host, port) do |http| # multiple requestsend
Ruby keeps the socket open.
Benefits:
- fewer TCP handshakes
- reduced latency
- improved performance
Internally:
- connection reuse
- keep-alive tracking
- socket lifecycle management
- EOF detection
are all implemented manually.
HTTPS Support
The file:
https.rb
bridges net/http with OpenSSL.
Example:
http.use_ssl = true
Internally Ruby:
- wraps the socket
- negotiates TLS
- validates certificates
- encrypts traffic
This tiny layer enables the entire HTTPS ecosystem.
Streaming Responses
Ruby can stream bodies incrementally:
http.request(request) do |response| response.read_body do |chunk| puts chunk endend
Internally this avoids loading entire payloads into memory.
Critical for:
- large downloads
- streaming APIs
- file transfers
- memory efficiency
Chunked Transfer Encoding
Ruby also implements HTTP chunked encoding.
Example wire protocol:
4Wiki5pedia0
The parser reconstructs the stream incrementally.
This is one of the more complex parts of HTTP handling.
Architectural Design Philosophy
The codebase reflects classic Ruby stdlib design:
- inheritance-heavy
- protocol-oriented
- object-modeled networking
- manual IO handling
- explicit abstractions
Unlike modern gems that hide implementation details, the stdlib exposes the protocol itself clearly.
Reading this code teaches:
- networking
- socket programming
- protocol design
- streaming IO
- HTTP semantics
—not just Ruby.
Some Particularly Interesting Internal Classes

What Makes This Codebase Valuable
Even today, modern libraries often build on top of these ideas.
Gems like:
- Faraday
- HTTParty
- HTTPX
- RestClient
still rely conceptually on:
- serialization
- transport abstraction
- response parsing
- persistent connections
The stdlib remains foundational knowledge.
Final Thoughts
Ruby’s net/http is far more than a convenience wrapper.
It is:
- a protocol engine
- a socket abstraction layer
- an HTTP parser
- a streaming framework
- an SSL client
- a transport architecture
implemented directly inside the standard library.
Reading this codebase reveals how much engineering exists beneath a simple:
Net::HTTP.get(uri)
And that’s exactly what makes exploring Ruby internals so rewarding.
