Skip to content

Commit 59cb277

Browse files
Clean up documentation.
1 parent 76200db commit 59cb277

File tree

7 files changed

+294
-70
lines changed

7 files changed

+294
-70
lines changed

context/getting-started.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Getting Started
2+
3+
This guide explains how to get started with `protocol-http1`, a low-level implementation of the HTTP/1 protocol for building HTTP clients and servers.
4+
5+
## Installation
6+
7+
Add the gem to your project:
8+
9+
```bash
10+
$ bundle add protocol-http1
11+
```
12+
13+
## Core Concepts
14+
15+
`protocol-http1` provides a low-level implementation of the HTTP/1 protocol with several core concepts:
16+
17+
- A {ruby Protocol::HTTP1::Connection} which represents the main entry point for creating HTTP/1.1 clients and servers.
18+
- Integration with the `Protocol::HTTP::Body` classes for handling request and response bodies.
19+
20+
## Usage
21+
22+
`protocol-http1` can be used to build both HTTP clients and servers.
23+
24+
### HTTP Server
25+
26+
Here's a simple HTTP/1.1 server that responds to all requests with "Hello World":
27+
28+
```ruby
29+
#!/usr/bin/env ruby
30+
31+
require "socket"
32+
require "protocol/http1/connection"
33+
require "protocol/http/body/buffered"
34+
35+
# Test with: curl http://localhost:8080/
36+
37+
Addrinfo.tcp("0.0.0.0", 8080).listen do |server|
38+
loop do
39+
client, address = server.accept
40+
connection = Protocol::HTTP1::Connection.new(client)
41+
42+
# Read request:
43+
while request = connection.read_request
44+
authority, method, path, version, headers, body = request
45+
46+
# Write response:
47+
connection.write_response(version, 200, [["content-type", "text/plain"]])
48+
connection.write_body(version, Protocol::HTTP::Body::Buffered.wrap(["Hello World"]))
49+
50+
break unless connection.persistent
51+
end
52+
end
53+
end
54+
```
55+
56+
The server:
57+
58+
1. Creates a new {ruby Protocol::HTTP1::Connection} for each client connection.
59+
2. Reads incoming requests using `read_request`.
60+
3. Sends responses using `write_response` and `write_body`.
61+
4. Supports persistent connections by checking `connection.persistent`.
62+
63+
### HTTP Client
64+
65+
Here's a simple HTTP/1.1 client that makes multiple requests:
66+
67+
```ruby
68+
#!/usr/bin/env ruby
69+
70+
require "async"
71+
require "async/http/endpoint"
72+
require "protocol/http1/connection"
73+
74+
Async do
75+
endpoint = Async::HTTP::Endpoint.parse("http://localhost:8080")
76+
77+
peer = endpoint.connect
78+
79+
puts "Connected to #{peer} #{peer.remote_address.inspect}"
80+
81+
# IO Buffering...
82+
client = Protocol::HTTP1::Connection.new(peer)
83+
84+
puts "Writing request..."
85+
3.times do
86+
client.write_request("localhost", "GET", "/", "HTTP/1.1", [["Accept", "*/*"]])
87+
client.write_body("HTTP/1.1", nil)
88+
89+
puts "Reading response..."
90+
response = client.read_response("GET")
91+
version, status, reason, headers, body = response
92+
93+
puts "Got response: #{response.inspect}"
94+
puts body&.read
95+
end
96+
97+
puts "Closing client..."
98+
client.close
99+
end
100+
```
101+
102+
The client:
103+
104+
1. Creates a connection to a server using `Async::HTTP::Endpoint`.
105+
2. Creates a {ruby Protocol::HTTP1::Connection} wrapper around the socket.
106+
3. Sends requests using `write_request` and `write_body`.
107+
4. Reads responses using `read_response`.
108+
5. Properly closes the connection when done.
109+
110+
### Connection Management
111+
112+
The {ruby Protocol::HTTP1::Connection} handles:
113+
114+
- **Request/Response Parsing**: Automatically parses HTTP/1.1 request and response formats.
115+
- **Persistent Connections**: Supports HTTP/1.1 keep-alive for multiple requests over one connection.
116+
- **Body Handling**: Integrates with `Protocol::HTTP::Body` classes for streaming and buffered content.
117+
- **Header Management**: Properly handles HTTP headers as arrays of key-value pairs.

context/index.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Automatically generated context index for Utopia::Project guides.
2+
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
3+
---
4+
description: A low level implementation of the HTTP/1 protocol.
5+
metadata:
6+
documentation_uri: https://socketry.github.io/protocol-http1/
7+
source_code_uri: https://github.com/socketry/protocol-http1.git
8+
files:
9+
- path: getting-started.md
10+
title: Getting Started
11+
description: This guide explains how to get started with `protocol-http1`, a low-level
12+
implementation of the HTTP/1 protocol for building HTTP clients and servers.

examples/early-hints/server.rb

Lines changed: 0 additions & 33 deletions
This file was deleted.

guides/getting-started/readme.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Getting Started
2+
3+
This guide explains how to get started with `protocol-http1`, a low-level implementation of the HTTP/1 protocol for building HTTP clients and servers.
4+
5+
## Installation
6+
7+
Add the gem to your project:
8+
9+
```bash
10+
$ bundle add protocol-http1
11+
```
12+
13+
## Core Concepts
14+
15+
`protocol-http1` provides a low-level implementation of the HTTP/1 protocol with several core concepts:
16+
17+
- A {ruby Protocol::HTTP1::Connection} which represents the main entry point for creating HTTP/1.1 clients and servers.
18+
- Integration with the `Protocol::HTTP::Body` classes for handling request and response bodies.
19+
20+
## Usage
21+
22+
`protocol-http1` can be used to build both HTTP clients and servers.
23+
24+
### HTTP Server
25+
26+
Here's a simple HTTP/1.1 server that responds to all requests with "Hello World":
27+
28+
```ruby
29+
#!/usr/bin/env ruby
30+
31+
require "socket"
32+
require "protocol/http1/connection"
33+
require "protocol/http/body/buffered"
34+
35+
# Test with: curl http://localhost:8080/
36+
37+
Addrinfo.tcp("0.0.0.0", 8080).listen do |server|
38+
loop do
39+
client, address = server.accept
40+
connection = Protocol::HTTP1::Connection.new(client)
41+
42+
# Read request:
43+
while request = connection.read_request
44+
authority, method, path, version, headers, body = request
45+
46+
# Write response:
47+
connection.write_response(version, 200, [["content-type", "text/plain"]])
48+
connection.write_body(version, Protocol::HTTP::Body::Buffered.wrap(["Hello World"]))
49+
50+
break unless connection.persistent
51+
end
52+
end
53+
end
54+
```
55+
56+
The server:
57+
58+
1. Creates a new {ruby Protocol::HTTP1::Connection} for each client connection.
59+
2. Reads incoming requests using `read_request`.
60+
3. Sends responses using `write_response` and `write_body`.
61+
4. Supports persistent connections by checking `connection.persistent`.
62+
63+
### HTTP Client
64+
65+
Here's a simple HTTP/1.1 client that makes multiple requests:
66+
67+
```ruby
68+
#!/usr/bin/env ruby
69+
70+
require "async"
71+
require "async/http/endpoint"
72+
require "protocol/http1/connection"
73+
74+
Async do
75+
endpoint = Async::HTTP::Endpoint.parse("http://localhost:8080")
76+
77+
peer = endpoint.connect
78+
79+
puts "Connected to #{peer} #{peer.remote_address.inspect}"
80+
81+
# IO Buffering...
82+
client = Protocol::HTTP1::Connection.new(peer)
83+
84+
puts "Writing request..."
85+
3.times do
86+
client.write_request("localhost", "GET", "/", "HTTP/1.1", [["Accept", "*/*"]])
87+
client.write_body("HTTP/1.1", nil)
88+
89+
puts "Reading response..."
90+
response = client.read_response("GET")
91+
version, status, reason, headers, body = response
92+
93+
puts "Got response: #{response.inspect}"
94+
puts body&.read
95+
end
96+
97+
puts "Closing client..."
98+
client.close
99+
end
100+
```
101+
102+
The client:
103+
104+
1. Creates a connection to a server using `Async::HTTP::Endpoint`.
105+
2. Creates a {ruby Protocol::HTTP1::Connection} wrapper around the socket.
106+
3. Sends requests using `write_request` and `write_body`.
107+
4. Reads responses using `read_response`.
108+
5. Properly closes the connection when done.
109+
110+
### Connection Management
111+
112+
The {ruby Protocol::HTTP1::Connection} handles:
113+
114+
- **Request/Response Parsing**: Automatically parses HTTP/1.1 request and response formats.
115+
- **Persistent Connections**: Supports HTTP/1.1 keep-alive for multiple requests over one connection.
116+
- **Body Handling**: Integrates with `Protocol::HTTP::Body` classes for streaming and buffered content.
117+
- **Header Management**: Properly handles HTTP headers as arrays of key-value pairs.

guides/links.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
getting-started:
2+
order: 1

protocol-http1.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
2020
"source_code_uri" => "https://github.com/socketry/protocol-http1.git",
2121
}
2222

23-
spec.files = Dir.glob(["{lib}/**/*", "*.md"], File::FNM_DOTMATCH, base: __dir__)
23+
spec.files = Dir.glob(["{context,lib}/**/*", "*.md"], File::FNM_DOTMATCH, base: __dir__)
2424

2525
spec.required_ruby_version = ">= 3.2"
2626

readme.md

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,46 +22,55 @@ Or install it yourself as:
2222

2323
## Usage
2424

25-
Here is a basic HTTP/1.1 client:
25+
Please see the [project documentation](https://socketry.github.io/protocol-http1/) for more details.
2626

27-
``` ruby
28-
require 'async'
29-
require 'async/io/stream'
30-
require 'async/http/endpoint'
31-
require 'protocol/http1/connection'
32-
33-
Async do
34-
endpoint = Async::HTTP::Endpoint.parse("https://www.google.com/search?q=kittens", alpn_protocols: ["http/1.1"])
35-
36-
peer = endpoint.connect
37-
38-
puts "Connected to #{peer} #{peer.remote_address.inspect}"
39-
40-
# IO Buffering...
41-
stream = Async::IO::Stream.new(peer)
42-
client = Protocol::HTTP1::Connection.new(stream)
43-
44-
def client.read_line
45-
@stream.read_until(Protocol::HTTP1::Connection::CRLF) or raise EOFError
46-
end
47-
48-
puts "Writing request..."
49-
client.write_request("www.google.com", "GET", "/search?q=kittens", "HTTP/1.1", [["Accept", "*/*"]])
50-
client.write_body(nil)
51-
52-
puts "Reading response..."
53-
response = client.read_response("GET")
54-
55-
puts "Got response: #{response.inspect}"
56-
57-
puts "Closing client..."
58-
client.close
59-
end
60-
```
27+
- [Getting Started](https://socketry.github.io/protocol-http1/guides/getting-started/index) - This guide explains how to get started with `protocol-http1`, a low-level implementation of the HTTP/1 protocol for building HTTP clients and servers.
6128

6229
## Releases
6330

64-
There are no documented releases.
31+
Please see the [project releases](https://socketry.github.io/protocol-http1/releases/index) for all releases.
32+
33+
### Unreleased
34+
35+
- Add traces provider for `Protocol::HTTP1::Connection`.
36+
37+
### v0.34.1
38+
39+
- Fix connection state handling to allow idempotent response body closing.
40+
- Add `kisaten` fuzzing integration for improved security testing.
41+
42+
### v0.34.0
43+
44+
- Support empty header values in HTTP parsing for better compatibility.
45+
46+
### v0.33.0
47+
48+
- Support high-byte characters in HTTP headers for improved international compatibility.
49+
50+
### v0.32.0
51+
52+
- Fix header parsing to handle tab characters between values correctly.
53+
- Complete documentation coverage for all public APIs.
54+
55+
### v0.31.0
56+
57+
- Enforce one-way transition for persistent connections to prevent invalid state changes.
58+
59+
### v0.30.0
60+
61+
- Make `authority` header optional in HTTP requests for improved flexibility.
62+
63+
### v0.29.0
64+
65+
- Add block/yield interface to `read_request` and `read_response` methods.
66+
67+
### v0.28.1
68+
69+
- Fix handling of `nil` lines in HTTP parsing.
70+
71+
### v0.28.0
72+
73+
- Add configurable maximum line length to prevent denial of service attacks.
6574

6675
## Contributing
6776

0 commit comments

Comments
 (0)