Skip to main content

decode/
decode.rs

1//! Example demonstrating HTTP request and response decoding.
2//!
3//! This example shows how to use `WireDecode` to parse raw HTTP bytes
4//! into structured request and response objects.
5//!
6//! Run with: cargo run --example decode
7
8use http_wire::WireDecode;
9use http_wire::request::FullRequest;
10use http_wire::response::FullResponse;
11use std::mem::MaybeUninit;
12
13fn main() {
14    println!("=== HTTP Decoding Examples ===\n");
15
16    // Example 1: Decode a simple GET request
17    println!("1. Decoding a simple GET request:");
18    println!("-----------------------------------");
19    decode_simple_request();
20    println!();
21
22    // Example 2: Decode a POST request with body
23    println!("2. Decoding a POST request with body:");
24    println!("--------------------------------------");
25    decode_post_request();
26    println!();
27
28    // Example 3: Decode using optimized uninit headers (Request only)
29    println!("3. Decoding with uninitialized headers (optimized):");
30    println!("---------------------------------------------------");
31    decode_request_optimized();
32    println!();
33
34    // Example 4: Decode a chunked request
35    println!("4. Decoding a chunked transfer-encoding request:");
36    println!("------------------------------------------------");
37    decode_chunked_request();
38    println!();
39
40    // Example 5: Decode HTTP responses
41    println!("5. Decoding HTTP responses:");
42    println!("---------------------------");
43    decode_responses();
44    println!();
45
46    // Example 6: Handling incomplete messages
47    println!("6. Handling incomplete messages:");
48    println!("--------------------------------");
49    handle_incomplete_messages();
50    println!();
51
52    println!("=== All examples completed successfully ===");
53}
54
55fn decode_simple_request() {
56    let raw = b"GET /api/users HTTP/1.1\r\nHost: example.com\r\nUser-Agent: curl/7.68.0\r\n\r\n";
57
58    // Allocate headers storage
59    let mut headers = [httparse::EMPTY_HEADER; 16];
60
61    match FullRequest::decode(raw, &mut headers) {
62        Ok((request, total_len)) => {
63            println!("✓ Successfully decoded request");
64            println!("  Method: {}", request.head.method.unwrap());
65            println!("  Path: {}", request.head.path.unwrap());
66            println!("  Version: HTTP/1.{}", request.head.version.unwrap());
67            println!("  Headers:");
68            for header in request.head.headers {
69                println!(
70                    "    {}: {}",
71                    header.name,
72                    String::from_utf8_lossy(header.value)
73                );
74            }
75            println!("  Body length: {} bytes", request.body.len());
76            println!("  Total message length: {} bytes", total_len);
77        }
78        Err(e) => eprintln!("✗ Error: {:?}", e),
79    }
80}
81
82fn decode_post_request() {
83    let raw = b"POST /api/users HTTP/1.1\r\nHost: example.com\r\nContent-Type: application/json\r\nContent-Length: 24\r\n\r\n{\"name\":\"John\",\"age\":30}";
84
85    let mut headers = [httparse::EMPTY_HEADER; 16];
86
87    match FullRequest::decode(raw, &mut headers) {
88        Ok((request, total_len)) => {
89            println!("✓ Successfully decoded POST request");
90            println!("  Method: {}", request.head.method.unwrap());
91            println!("  Path: {}", request.head.path.unwrap());
92            println!("  Headers:");
93            for header in request.head.headers {
94                println!(
95                    "    {}: {}",
96                    header.name,
97                    String::from_utf8_lossy(header.value)
98                );
99            }
100            println!("  Body: {}", String::from_utf8_lossy(request.body));
101            println!("  Total length: {} bytes", total_len);
102        }
103        Err(e) => eprintln!("✗ Error: {:?}", e),
104    }
105}
106
107fn decode_request_optimized() {
108    let raw =
109        b"GET /api/data HTTP/1.1\r\nHost: api.example.com\r\nAccept: application/json\r\n\r\n";
110
111    // Use uninitialized headers for maximum performance
112    // This avoids the overhead of initializing the headers array
113    let mut headers = [const { MaybeUninit::uninit() }; 16];
114
115    match FullRequest::decode_uninit(raw, &mut headers) {
116        Ok((request, total_len)) => {
117            println!("✓ Successfully decoded with uninit headers (faster!)");
118            println!("  Method: {}", request.head.method.unwrap());
119            println!("  Path: {}", request.head.path.unwrap());
120            println!("  Headers count: {}", request.head.headers.len());
121            println!("  Total length: {} bytes", total_len);
122            println!();
123            println!("  Note: decode_uninit() is faster because it skips header");
124            println!("        initialization. Use this for performance-critical code.");
125        }
126        Err(e) => eprintln!("✗ Error: {:?}", e),
127    }
128}
129
130fn decode_chunked_request() {
131    let raw = b"POST /api/upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n";
132
133    let mut headers = [httparse::EMPTY_HEADER; 16];
134
135    match FullRequest::decode(raw, &mut headers) {
136        Ok((request, total_len)) => {
137            println!("✓ Successfully decoded chunked request");
138            println!("  Method: {}", request.head.method.unwrap());
139            println!("  Transfer-Encoding: chunked");
140            println!(
141                "  Raw body (with chunk markers): {} bytes",
142                request.body.len()
143            );
144            println!("  Total length (including chunks): {} bytes", total_len);
145            println!();
146            println!("  Note: request.body contains the raw chunked data including");
147            println!("        chunk size markers. Use a chunked decoder to extract");
148            println!("        the actual content if needed.");
149        }
150        Err(e) => eprintln!("✗ Error: {:?}", e),
151    }
152}
153
154fn decode_responses() {
155    // Example 1: 200 OK with body
156    let raw = b"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 15\r\n\r\n{\"status\":\"ok\"}";
157    let mut headers = [httparse::EMPTY_HEADER; 16];
158
159    match FullResponse::decode(raw, &mut headers) {
160        Ok((response, total_len)) => {
161            println!("✓ 200 OK Response:");
162            println!("  Status: {}", response.head.code.unwrap());
163            println!("  Reason: {}", response.head.reason.unwrap());
164            println!("  Body: {}", String::from_utf8_lossy(response.body));
165            println!("  Total length: {} bytes", total_len);
166        }
167        Err(e) => eprintln!("✗ Error: {:?}", e),
168    }
169
170    println!();
171
172    // Example 2: 404 Not Found
173    let raw = b"HTTP/1.1 404 Not Found\r\nContent-Length: 9\r\n\r\nNot Found";
174    let mut headers = [httparse::EMPTY_HEADER; 16];
175
176    match FullResponse::decode(raw, &mut headers) {
177        Ok((response, _)) => {
178            println!("✓ 404 Response:");
179            println!("  Status: {}", response.head.code.unwrap());
180            println!("  Reason: {}", response.head.reason.unwrap());
181            println!("  Body: {}", String::from_utf8_lossy(response.body));
182        }
183        Err(e) => eprintln!("✗ Error: {:?}", e),
184    }
185
186    println!();
187
188    // Example 3: 204 No Content (no body)
189    let raw = b"HTTP/1.1 204 No Content\r\nServer: nginx\r\n\r\n";
190    let mut headers = [httparse::EMPTY_HEADER; 16];
191
192    match FullResponse::decode(raw, &mut headers) {
193        Ok((response, _)) => {
194            println!("✓ 204 No Content Response:");
195            println!("  Status: {}", response.head.code.unwrap());
196            println!(
197                "  Body length: {} bytes (correct for 204)",
198                response.body.len()
199            );
200        }
201        Err(e) => eprintln!("✗ Error: {:?}", e),
202    }
203
204    println!();
205
206    // Note about decode_uninit for responses
207    println!("  Note: FullResponse does NOT support decode_uninit() because");
208    println!("        httparse::Response lacks parse_with_uninit_headers method.");
209    println!("        Attempting to use it will panic with a clear error message.");
210}
211
212fn handle_incomplete_messages() {
213    // Example 1: Incomplete headers
214    let raw = b"GET /api/test HTTP/1.1\r\nHost: example.com\r\n";
215    let mut headers = [httparse::EMPTY_HEADER; 16];
216
217    match FullRequest::decode(raw, &mut headers) {
218        Ok(_) => println!("✗ Should have failed!"),
219        Err(e) => println!("✓ Correctly detected incomplete headers: {:?}", e),
220    }
221
222    // Example 2: Incomplete body
223    let raw = b"POST /api/test HTTP/1.1\r\nHost: example.com\r\nContent-Length: 100\r\n\r\nshort";
224    let mut headers = [httparse::EMPTY_HEADER; 16];
225
226    match FullRequest::decode(raw, &mut headers) {
227        Ok(_) => println!("✗ Should have failed!"),
228        Err(e) => println!("✓ Correctly detected incomplete body: {:?}", e),
229    }
230
231    println!();
232    println!("  These errors allow you to buffer more data and retry parsing");
233    println!("  when working with streaming sockets or incremental data.");
234}