protocol-http 0.51.1 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7152574d762fbdc22baa9dcd2f9d22931a2da4a9b3e0727af9580b7bebe31a1e
4
- data.tar.gz: 8a704017b5e0897741233497d779a40eba812357238105bef7910090c08cf7a3
3
+ metadata.gz: 9e1927ee19fba11fbeb421268490fabcde86d7ef9ca5d472320b9aaad6763892
4
+ data.tar.gz: fe4c304a05ce7c3637ad460e976dbbf114c22dfb49fe425f9a2dbde1cf280d35
5
5
  SHA512:
6
- metadata.gz: 7bd538f9a03da7137f2f58c77777859b5a2b6b14bef08f055104427d9c029d4bc75912dcd10f8e385680c127439c78e6980436ee9200656f0a41b8d2342de0e8
7
- data.tar.gz: 8a00a43b390046bba90ce8c523aa99cf5aff1a2fd1b3c6b3f480538ef9a201c2c9a6ef5646558feb649625498c95a224ef9ec1c1bfa78caa29f2b1a6128a7e55
6
+ metadata.gz: 97d19c21e2d67d5870077b7ae2856438a1e4314934f01bc93148f63be4db4d55ffee18f45f66ed7b0665678dd8b0deb4718cda92fd9334f198bb2fa335bb297f
7
+ data.tar.gz: 674bd9d94d4efacde5d42d8c02dd8876f7f8f96290a26051343103c11f6e68ae54678746bf6d034071c0bba3a5dd7263affecc8c3e86be9ec1766faefc93e50a
checksums.yaml.gz.sig CHANGED
Binary file
data/agent.md ADDED
@@ -0,0 +1,145 @@
1
+ # Agent
2
+
3
+ ## Context
4
+
5
+ This section provides links to documentation from installed packages. It is automatically generated and may be updated by running `bake agent:context:install`.
6
+
7
+ **Important:** Before performing any code, documentation, or analysis tasks, always read and apply the full content of any relevant documentation referenced in the following sections. These context files contain authoritative standards and best practices for documentation, code style, and project-specific workflows. **Do not proceed with any actions until you have read and incorporated the guidance from relevant context files.**
8
+
9
+ **Setup Instructions:** If the referenced files are not present or if dependencies have been updated, run `bake agent:context:install` to install the latest context files.
10
+
11
+ ### agent-context
12
+
13
+ Install and manage context files from Ruby gems.
14
+
15
+ #### [Getting Started](.context/agent-context/getting-started.md)
16
+
17
+ This guide explains how to use `agent-context`, a tool for discovering and installing contextual information from Ruby gems to help AI agents.
18
+
19
+ ### async
20
+
21
+ A concurrency framework for Ruby.
22
+
23
+ #### [Getting Started](.context/async/getting-started.md)
24
+
25
+ This guide shows how to add async to your project and run code asynchronously.
26
+
27
+ #### [Scheduler](.context/async/scheduler.md)
28
+
29
+ This guide gives an overview of how the scheduler is implemented.
30
+
31
+ #### [Tasks](.context/async/tasks.md)
32
+
33
+ This guide explains how asynchronous tasks work and how to use them.
34
+
35
+ #### [Best Practices](.context/async/best-practices.md)
36
+
37
+ This guide gives an overview of best practices for using Async.
38
+
39
+ #### [Debugging](.context/async/debugging.md)
40
+
41
+ This guide explains how to debug issues with programs that use Async.
42
+
43
+ #### [Thread safety](.context/async/thread-safety.md)
44
+
45
+ This guide explains thread safety in Ruby, focusing on fibers and threads, common pitfalls, and best practices to avoid problems like data corruption, race conditions, and deadlocks.
46
+
47
+ ### async-service
48
+
49
+ A service layer for Async.
50
+
51
+ #### [Getting Started](.context/async-service/getting-started.md)
52
+
53
+ This guide explains how to get started with `async-service` to create and run services in Ruby.
54
+
55
+ #### [Service Architecture](.context/async-service/service-architecture.md)
56
+
57
+ This guide explains the key architectural components of `async-service` and how they work together to provide a clean separation of concerns.
58
+
59
+ #### [Best Practices](.context/async-service/best-practices.md)
60
+
61
+ This guide outlines recommended patterns and practices for building robust, maintainable services with `async-service`.
62
+
63
+ ### decode
64
+
65
+ Code analysis for documentation generation.
66
+
67
+ #### [Getting Started with Decode](.context/decode/getting-started.md)
68
+
69
+ The Decode gem provides programmatic access to Ruby code structure and metadata. It can parse Ruby files and extract definitions, comments, and documentation pragmas, enabling code analysis, documentation generation, and other programmatic manipulations of Ruby codebases.
70
+
71
+ #### [Documentation Coverage](.context/decode/coverage.md)
72
+
73
+ This guide explains how to test and monitor documentation coverage in your Ruby projects using the Decode gem's built-in bake tasks.
74
+
75
+ #### [Ruby Documentation](.context/decode/ruby-documentation.md)
76
+
77
+ This guide covers documentation practices and pragmas supported by the Decode gem for documenting Ruby code. These pragmas provide structured documentation that can be parsed and used to generate API documentation and achieve complete documentation coverage.
78
+
79
+ #### [Setting Up RBS Types and Steep Type Checking for Ruby Gems](.context/decode/types.md)
80
+
81
+ This guide covers the process for establishing robust type checking in Ruby gems using RBS and Steep, focusing on automated generation from source documentation and proper validation.
82
+
83
+ ### falcon
84
+
85
+ A fast, asynchronous, rack-compatible web server.
86
+
87
+ #### [Getting Started](.context/falcon/getting-started.md)
88
+
89
+ This guide gives an overview of how to use Falcon for running Ruby web applications.
90
+
91
+ #### [Rails Integration](.context/falcon/rails-integration.md)
92
+
93
+ This guide explains how to host Rails applications with Falcon.
94
+
95
+ #### [Deployment](.context/falcon/deployment.md)
96
+
97
+ This guide explains how to deploy applications using the Falcon web server. It covers the recommended deployment methods, configuration options, and examples for different environments, including systemd and kubernetes.
98
+
99
+ #### [Performance Tuning](.context/falcon/performance-tuning.md)
100
+
101
+ This guide explains the performance characteristics of Falcon.
102
+
103
+ #### [WebSockets](.context/falcon/websockets.md)
104
+
105
+ This guide explains how to use WebSockets with Falcon.
106
+
107
+ #### [Interim Responses](.context/falcon/interim-responses.md)
108
+
109
+ This guide explains how to use interim responses in Falcon to send early hints to the client.
110
+
111
+ #### [How It Works](.context/falcon/how-it-works.md)
112
+
113
+ This guide gives an overview of how Falcon handles an incoming web request.
114
+
115
+ ### sus
116
+
117
+ A fast and scalable test runner.
118
+
119
+ #### [Using Sus Testing Framework](.context/sus/usage.md)
120
+
121
+ Sus is a modern Ruby testing framework that provides a clean, BDD-style syntax for writing tests. It's designed to be fast, simple, and expressive.
122
+
123
+ #### [Mocking](.context/sus/mocking.md)
124
+
125
+ There are two types of mocking in sus: `receive` and `mock`. The `receive` matcher is a subset of full mocking and is used to set expectations on method calls, while `mock` can be used to replace method implementations or set up more complex behavior.
126
+
127
+ #### [Shared Test Behaviors and Fixtures](.context/sus/shared.md)
128
+
129
+ Sus provides shared test contexts which can be used to define common behaviours or tests that can be reused across one or more test files.
130
+
131
+ ### utopia-project
132
+
133
+ A project documentation tool based on Utopia.
134
+
135
+ #### [Getting Started](.context/utopia-project/getting-started.md)
136
+
137
+ This guide explains how to use `utopia-project` to add documentation to your project.
138
+
139
+ #### [Documentation Guides](.context/utopia-project/documentation-guidelines.md)
140
+
141
+ This guide explains how to create and maintain documentation for your project using `utopia-project`.
142
+
143
+ #### [GitHub Pages Integration](.context/utopia-project/github-pages-integration.md)
144
+
145
+ This guide shows you how to use `utopia-project` with GitHub Pages to deploy documentation.
@@ -0,0 +1,209 @@
1
+ # Design Overview
2
+
3
+ This guide explains the high level design of `protocol-http` in the context of wider design patterns that can be used to implement HTTP clients and servers.
4
+
5
+ ## Request/Response Model
6
+
7
+ The main model we support is the request/response model. A client sends a request to a server which return response. The protocol is responsible for serializing the request and response objects.
8
+
9
+ ```mermaid
10
+ sequenceDiagram
11
+ participant CA as Application
12
+ participant Client
13
+ participant Server
14
+ participant SA as Application
15
+ CA->>+Client: Request
16
+ Client->>+Server: Request
17
+ Server->>+SA: Request
18
+ SA->>+Server: Response
19
+ Server->>+Client: Response
20
+ Client->>+CA: Response
21
+ ```
22
+
23
+ We provide an interface for request and response objects. This provides performance, predictability and robustness. This model has proven itself over several years, handling a variety of different use cases.
24
+
25
+ ~~~ ruby
26
+ class Request
27
+ attr :method
28
+ attr :target
29
+ attr :headers
30
+ attr :body
31
+ end
32
+
33
+ class Response
34
+ attr :status
35
+ attr :headers
36
+ attr :body
37
+ end
38
+ ~~~
39
+
40
+ One other advantage is that it's symmetrical between clients and servers with a clear mapping, i.e. the protocol is responsible for transiting requests from the client to the server, and responses from the server back to the client. This helps us separate and define request/response interfaces independently from protocol implementation.
41
+
42
+ ### Client Design
43
+
44
+ A request/response model implies that you create a request and receive a response back. This maps to a normal function call where the request is the argument and the response is the returned value.
45
+
46
+ ~~~ ruby
47
+ request = Request.new("GET", url)
48
+ response = client.call(request)
49
+
50
+ response.headers
51
+ response.read
52
+ ~~~
53
+
54
+ ## Stream Model
55
+
56
+ An alternative model is the stream model. This model is more suitable for WebSockets and other persistent bi-directional channels.
57
+
58
+ ```mermaid
59
+ sequenceDiagram
60
+ participant CA as Application
61
+ participant Client
62
+ participant Server
63
+ participant SA as Application
64
+ CA->>+Client: Stream
65
+ Client->>+Server: Stream
66
+ Server->>+SA: Stream
67
+ ```
68
+
69
+ The interfaces for streaming can be implemented a bit differently, since a response is not returned but rather assigned to the stream, and the streaming occurs in the same execution context as the client or server handling the request.
70
+
71
+ ~~~ ruby
72
+ class Stream
73
+ # Request details.
74
+ attr :method
75
+ attr :target
76
+ attr :headers
77
+
78
+ attr :response
79
+
80
+ # Write the response and start streaming the output body.
81
+ def respond(status, headers)
82
+ response.status = status
83
+ response.headers = headers
84
+ end
85
+
86
+ # Request body.
87
+ attr_accessor :input
88
+
89
+ # Response body.
90
+ attr_accessor :output
91
+
92
+ # Write to the response body.
93
+ def write(...)
94
+ @output.write(...)
95
+ end
96
+
97
+ # Read from the request body.
98
+ def read
99
+ @input.read
100
+ end
101
+ end
102
+
103
+ class Response
104
+ def initialize(method, target)
105
+ @input = Body::Writable.new
106
+ @output = Body::Writable.new
107
+ end
108
+
109
+ attr_accessor :status
110
+ attr_accessor :headers
111
+
112
+ # Prepare a stream for making a request.
113
+ def request(method, target, headers)
114
+ # Create a request stream suitable for writing into the buffered response:
115
+ Stream.new(method, target, headers, self, @input, @output)
116
+ end
117
+
118
+ # Write to the request body.
119
+ def write(...)
120
+ @input.write(...)
121
+ end
122
+
123
+ # Read from the response body.
124
+ def read
125
+ @output.read
126
+ end
127
+ end
128
+ ~~~
129
+
130
+ ### Client Design
131
+
132
+ A stream model implies that you create a stream which contains both the request and response bodies. This maps to a normal function call where the argument is the stream and the returned value is ignored.
133
+
134
+ ~~~ ruby
135
+ response = Response.new
136
+ stream = response.request("GET", url)
137
+
138
+ client.call(stream)
139
+
140
+ response.headers
141
+ response.read
142
+ ~~~
143
+
144
+ ## Differences
145
+
146
+ The request/response model has a symmetrical design which naturally uses the return value for the result of executing the request. The result encapsulates the behaviour of how to read the response status, headers and body. Because of that, streaming input and output becomes a function of the result object itself. As in:
147
+
148
+ ~~~ ruby
149
+ def call(request)
150
+ body = Body::Writable.new
151
+
152
+ Fiber.schedule do
153
+ while chunk = request.input.read
154
+ body.write(chunk.reverse)
155
+ end
156
+ end
157
+
158
+ return Response[200, headers, body]
159
+ end
160
+
161
+ input = Body::Writable.new
162
+ response = call(... body ...)
163
+
164
+ input.write("Hello World")
165
+ input.close
166
+ response.read -> "dlroW olleH"
167
+ ~~~
168
+
169
+ The streaming model does not have the same symmetry, and instead opts for a uni-directional flow of information.
170
+
171
+ ~~~ruby
172
+ def call(stream)
173
+ stream.respond(200, headers)
174
+
175
+ Fiber.schedule do
176
+ while chunk = stream.read
177
+ stream.write(chunk.reverse)
178
+ end
179
+ end
180
+ end
181
+
182
+ input = Body::Writable.new
183
+ response = Response.new(...input...)
184
+ call(response.stream)
185
+
186
+ input.write("Hello World")
187
+ input.close
188
+ response.read -> "dlroW olleH"
189
+ ~~~
190
+
191
+ The value of this uni-directional flow is that it is natural for the stream to be taken out of the scope imposed by the nested `call(request)` model. However, the user must explicitly close the stream, since it's no longer scoped to the client and/or server.
192
+
193
+ ## Interim Response Handling
194
+
195
+ Interim responses are responses that are sent before the final response. They are used for things like `103 Early Hints` and `100 Continue`. These responses are sent before the final response, and are used to signal to the client that the server is still processing the request.
196
+
197
+ ```ruby
198
+ body = Body::Writable.new
199
+
200
+ interim_response_callback = proc do |status, headers|
201
+ if status == 100
202
+ # Continue sending the request body.
203
+ body.write("Hello World")
204
+ body.close
205
+ end
206
+ end
207
+
208
+ response = client.post("/upload", {'expect' => '100-continue'}, body, interim_response: interim_response_callback)
209
+ ```
@@ -0,0 +1,130 @@
1
+ # Getting Started
2
+
3
+ This guide explains how to use `protocol-http` for building abstract HTTP interfaces.
4
+
5
+ ## Installation
6
+
7
+ Add the gem to your project:
8
+
9
+ ~~~ bash
10
+ $ bundle add protocol-http
11
+ ~~~
12
+
13
+ ## Core Concepts
14
+
15
+ `protocol-http` has several core concepts:
16
+
17
+ - A {ruby Protocol::HTTP::Request} instance which represents an abstract HTTP request. Specific versions of HTTP may subclass this to track additional state.
18
+ - A {ruby Protocol::HTTP::Response} instance which represents an abstract HTTP response. Specific versions of HTTP may subclass this to track additional state.
19
+ - A {ruby Protocol::HTTP::Middleware} interface for building HTTP applications.
20
+ - A {ruby Protocol::HTTP::Headers} interface for storing HTTP headers with semantics based on documented specifications (RFCs, etc).
21
+ - A set of {ruby Protocol::HTTP::Body} classes which handle the internal request and response bodies, including bi-directional streaming.
22
+
23
+ ## Integration
24
+
25
+ This gem does not provide any specific client or server implementation, rather it's used by several other gems.
26
+
27
+ - [Protocol::HTTP1](https://github.com/socketry/protocol-http1) & [Protocol::HTTP2](https://github.com/socketry/protocol-http2) which provide client and server implementations.
28
+ - [Async::HTTP](https://github.com/socketry/async-http) which provides connection pooling and concurrency.
29
+
30
+ ## Usage
31
+
32
+ ### Request
33
+
34
+ {ruby Protocol::HTTP::Request} represents an HTTP request which can be used both server and client-side.
35
+
36
+ ``` ruby
37
+ require 'protocol/http/request'
38
+
39
+ # Short form (recommended):
40
+ request = Protocol::HTTP::Request["GET", "/index.html", {"accept" => "text/html"}]
41
+
42
+ # Long form:
43
+ headers = Protocol::HTTP::Headers[["accept", "text/html"]]
44
+ request = Protocol::HTTP::Request.new("http", "example.com", "GET", "/index.html", "HTTP/1.1", headers)
45
+
46
+ # Access request properties
47
+ request.method # => "GET"
48
+ request.path # => "/index.html"
49
+ request.headers # => Protocol::HTTP::Headers instance
50
+ ```
51
+
52
+ ### Response
53
+
54
+ {ruby Protocol::HTTP::Response} represents an HTTP response which can be used both server and client-side.
55
+
56
+ ``` ruby
57
+ require 'protocol/http/response'
58
+
59
+ # Short form (recommended):
60
+ response = Protocol::HTTP::Response[200, {"content-type" => "text/html"}, "Hello, World!"]
61
+
62
+ # Long form:
63
+ headers = Protocol::HTTP::Headers["content-type" => "text/html"]
64
+ body = Protocol::HTTP::Body::Buffered.wrap("Hello, World!")
65
+ response = Protocol::HTTP::Response.new("HTTP/1.1", 200, headers, body)
66
+
67
+ # Access response properties
68
+ response.status # => 200
69
+ response.headers # => Protocol::HTTP::Headers instance
70
+ response.body # => Body instance
71
+
72
+ # Status checking methods
73
+ response.success? # => true (200-299)
74
+ response.ok? # => true (200)
75
+ response.redirection? # => false (300-399)
76
+ response.failure? # => false (400-599)
77
+ ```
78
+
79
+ ### Headers
80
+
81
+ {ruby Protocol::HTTP::Headers} provides semantically meaningful interpretation of header values and implements case-normalising keys.
82
+
83
+ #### Basic Usage
84
+
85
+ ``` ruby
86
+ require 'protocol/http/headers'
87
+
88
+ headers = Protocol::HTTP::Headers.new
89
+
90
+ # Assignment by title-case key:
91
+ headers['Content-Type'] = "image/jpeg"
92
+
93
+ # Lookup by lower-case (normalized) key:
94
+ headers['content-type']
95
+ # => "image/jpeg"
96
+ ```
97
+
98
+ #### Semantic Processing
99
+
100
+ Many headers receive special semantic processing, automatically splitting comma-separated values and providing structured access:
101
+
102
+ ``` ruby
103
+ # Accept header with quality values:
104
+ headers['Accept'] = 'text/html, application/json;q=0.8, */*;q=0.1'
105
+ accept = headers['accept']
106
+ # => ["text/html", "application/json;q=0.8", "*/*;q=0.1"]
107
+
108
+ # Access parsed media ranges with quality factors:
109
+ accept.media_ranges.each do |range|
110
+ puts "#{range.type}/#{range.subtype} (q=#{range.quality_factor})"
111
+ end
112
+ # text/html (q=1.0)
113
+ # application/json (q=0.8)
114
+ # */* (q=0.1)
115
+
116
+ # Accept-Encoding automatically splits values:
117
+ headers['Accept-Encoding'] = 'gzip, deflate, br;q=0.9'
118
+ headers['accept-encoding']
119
+ # => ["gzip", "deflate", "br;q=0.9"]
120
+
121
+ # Cache-Control splits directives:
122
+ headers['Cache-Control'] = 'max-age=3600, no-cache, must-revalidate'
123
+ headers['cache-control']
124
+ # => ["max-age=3600", "no-cache", "must-revalidate"]
125
+
126
+ # Vary header normalizes field names to lowercase:
127
+ headers['Vary'] = 'Accept-Encoding, User-Agent'
128
+ headers['vary']
129
+ # => ["accept-encoding", "user-agent"]
130
+ ```
@@ -0,0 +1,140 @@
1
+ # Hypertext References
2
+
3
+ This guide explains how to use `Protocol::HTTP::Reference` for constructing and manipulating hypertext references (URLs with parameters).
4
+
5
+ ## Overview
6
+
7
+ {ruby Protocol::HTTP::Reference} is used to construct "hypertext references" which consist of a path and URL-encoded parameters. References provide a rich API for URL construction, path manipulation, and parameter handling.
8
+
9
+ ## Basic Construction
10
+
11
+ ``` ruby
12
+ require 'protocol/http/reference'
13
+
14
+ # Simple reference with parameters:
15
+ reference = Protocol::HTTP::Reference.new("/search", nil, nil, {q: 'kittens', limit: 10})
16
+ reference.to_s
17
+ # => "/search?q=kittens&limit=10"
18
+
19
+ # Parse existing URLs:
20
+ reference = Protocol::HTTP::Reference.parse("/api/users?page=2&sort=name#results")
21
+ reference.path # => "/api/users"
22
+ reference.query # => "page=2&sort=name"
23
+ reference.fragment # => "results"
24
+
25
+ # To get parameters as a hash, decode the query string:
26
+ parameters = Protocol::HTTP::URL.decode(reference.query)
27
+ parameters # => {"page" => "2", "sort" => "name"}
28
+ ```
29
+
30
+ ## Path Manipulation
31
+
32
+ References support sophisticated path manipulation including relative path resolution:
33
+
34
+ ``` ruby
35
+ base = Protocol::HTTP::Reference.new("/api/v1/users")
36
+
37
+ # Append paths:
38
+ user_detail = base.with(path: "123")
39
+ user_detail.to_s # => "/api/v1/users/123"
40
+
41
+ # Relative path navigation:
42
+ parent = user_detail.with(path: "../groups", pop: true)
43
+ parent.to_s # => "/api/v1/groups"
44
+
45
+ # Absolute path replacement:
46
+ root = user_detail.with(path: "/status")
47
+ root.to_s # => "/status"
48
+ ```
49
+
50
+ ## Advanced Parameter Handling
51
+
52
+ ``` ruby
53
+ # Complex parameter structures:
54
+ reference = Protocol::HTTP::Reference.new("/search", nil, nil, {
55
+ filters: {
56
+ category: "books",
57
+ price: {min: 10, max: 50}
58
+ },
59
+ tags: ["fiction", "mystery"]
60
+ })
61
+
62
+ reference.to_s
63
+ # => "/search?filters[category]=books&filters[price][min]=10&filters[price][max]=50&tags[]=fiction&tags[]=mystery"
64
+
65
+ # Parameter merging:
66
+ base = Protocol::HTTP::Reference.new("/api", nil, nil, {version: "v1", format: "json"})
67
+ extended = base.with(parameters: {detailed: true}, merge: true)
68
+ extended.to_s
69
+ # => "/api?version=v1&format=json&detailed=true"
70
+
71
+ # Parameter replacement (using merge: false):
72
+ replaced = base.with(parameters: {format: "xml"}, merge: false)
73
+ replaced.to_s
74
+ # => "/api?format=xml"
75
+ ```
76
+
77
+ ## Merge Behavior and Query Strings
78
+
79
+ The `merge` parameter controls both parameter handling and query string behavior:
80
+
81
+ ``` ruby
82
+ # Create a reference with both query string and parameters:
83
+ ref = Protocol::HTTP::Reference.new("/api", "existing=query", nil, {version: "v1"})
84
+ ref.to_s
85
+ # => "/api?existing=query&version=v1"
86
+
87
+ # merge: true (default) - keeps existing query string:
88
+ merged = ref.with(parameters: {new: "argument"}, merge: true)
89
+ merged.to_s
90
+ # => "/api?existing=query&version=v1&new=argument"
91
+
92
+ # merge: false with new parameters - clears query string:
93
+ replaced = ref.with(parameters: {new: "argument"}, merge: false)
94
+ replaced.to_s
95
+ # => "/api?new=argument"
96
+
97
+ # merge: false without new parameters - keeps everything:
98
+ unchanged = ref.with(path: "v2", merge: false)
99
+ unchanged.to_s
100
+ # => "/api/v2?existing=query&version=v1"
101
+ ```
102
+
103
+ ## URL Encoding and Special Characters
104
+
105
+ References handle URL encoding automatically:
106
+
107
+ ``` ruby
108
+ # Spaces and special characters:
109
+ reference = Protocol::HTTP::Reference.new("/search", nil, nil, {
110
+ q: "hello world",
111
+ filter: "price > $10"
112
+ })
113
+ reference.to_s
114
+ # => "/search?q=hello%20world&filter=price%20%3E%20%2410"
115
+
116
+ # Unicode support:
117
+ unicode_ref = Protocol::HTTP::Reference.new("/files", nil, nil, {
118
+ name: "résumé.pdf",
119
+ emoji: "😀"
120
+ })
121
+ unicode_ref.to_s
122
+ # => "/files?name=r%C3%A9sum%C3%A9.pdf&emoji=%F0%9F%98%80"
123
+ ```
124
+
125
+ ## Reference Merging
126
+
127
+ References can be merged following RFC2396 URI resolution rules:
128
+
129
+ ``` ruby
130
+ base = Protocol::HTTP::Reference.new("/docs/guide/")
131
+ relative = Protocol::HTTP::Reference.new("../api/reference.html")
132
+
133
+ merged = base + relative
134
+ merged.to_s # => "/docs/api/reference.html"
135
+
136
+ # Absolute references override completely
137
+ absolute = Protocol::HTTP::Reference.new("/completely/different/path")
138
+ result = base + absolute
139
+ result.to_s # => "/completely/different/path"
140
+ ```
@@ -0,0 +1,36 @@
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: Provides abstractions to handle HTTP protocols.
5
+ metadata:
6
+ documentation_uri: https://socketry.github.io/protocol-http/
7
+ source_code_uri: https://github.com/socketry/protocol-http.git
8
+ files:
9
+ - path: getting-started.md
10
+ title: Getting Started
11
+ description: This guide explains how to use `protocol-http` for building abstract
12
+ HTTP interfaces.
13
+ - path: message-body.md
14
+ title: Message Body
15
+ description: This guide explains how to work with HTTP request and response message
16
+ bodies using `Protocol::HTTP::Body` classes.
17
+ - path: middleware.md
18
+ title: Middleware
19
+ description: This guide explains how to build and use HTTP middleware with `Protocol::HTTP::Middleware`.
20
+ - path: hypertext-references.md
21
+ title: Hypertext References
22
+ description: This guide explains how to use `Protocol::HTTP::Reference` for constructing
23
+ and manipulating hypertext references (URLs with parameters).
24
+ - path: url-parsing.md
25
+ title: URL Parsing
26
+ description: This guide explains how to use `Protocol::HTTP::URL` for parsing and
27
+ manipulating URL components, particularly query strings and parameters.
28
+ - path: streaming.md
29
+ title: Streaming
30
+ description: This guide gives an overview of how to implement streaming requests
31
+ and responses.
32
+ - path: design-overview.md
33
+ title: Design Overview
34
+ description: This guide explains the high level design of `protocol-http` in the
35
+ context of wider design patterns that can be used to implement HTTP clients and
36
+ servers.