0
# Request and Response APIs
1
2
The request and response APIs provide the core interfaces for handling HTTP requests and generating responses, including content processing, header management, and lifecycle callbacks.
3
4
## Request Interface
5
6
The `Request` interface represents an HTTP request with content, headers, and context.
7
8
```java { .api }
9
public interface Request extends Attributes, Content.Source {
10
// Request identification and metadata
11
String getId();
12
Components getComponents();
13
ConnectionMetaData getConnectionMetaData();
14
15
// HTTP method and URI
16
String getMethod();
17
HttpURI getHttpURI();
18
19
// Request context
20
Context getContext();
21
22
// Headers and cookies
23
HttpFields getHeaders();
24
List<HttpCookie> getCookies();
25
26
// Session management
27
Session getSession(boolean create);
28
29
// Content handling (from Content.Source)
30
Content.Chunk read();
31
void demand(Runnable demandCallback);
32
void fail(Throwable failure);
33
34
// Nested interfaces
35
interface Handler {
36
boolean handle(Request request, Response response, Callback callback) throws Exception;
37
}
38
39
interface Wrapper extends Request {
40
Request getWrapped();
41
}
42
}
43
```
44
45
## Response Interface
46
47
The `Response` interface represents an HTTP response with status, headers, and content writing capabilities.
48
49
```java { .api }
50
public interface Response extends Content.Sink {
51
// Request association
52
Request getRequest();
53
54
// Status management
55
int getStatus();
56
void setStatus(int code);
57
58
// Header management
59
HttpFields.Mutable getHeaders();
60
61
// Content writing (from Content.Sink)
62
void write(boolean last, ByteBuffer byteBuffer, Callback callback);
63
64
// Error handling
65
Runnable writeError(Request request, Response response, Callback callback,
66
int code, String message);
67
68
// Response state
69
boolean isCommitted();
70
boolean isCompleted();
71
long getBytesWritten();
72
73
// Nested classes
74
class Wrapper implements Response {
75
public Response getWrapped();
76
}
77
}
78
```
79
80
## Usage Examples
81
82
### Basic Request Handling
83
84
```java
85
public class SimpleHandler extends Handler.Abstract {
86
@Override
87
public boolean handle(Request request, Response response, Callback callback)
88
throws Exception {
89
// Get request information
90
String method = request.getMethod();
91
String path = request.getHttpURI().getPath();
92
String userAgent = request.getHeaders().get("User-Agent");
93
94
System.out.println("Request: " + method + " " + path);
95
System.out.println("User-Agent: " + userAgent);
96
97
// Set response
98
response.setStatus(200);
99
response.getHeaders().put("Content-Type", "text/html");
100
101
String html = "<html><body><h1>Hello from Jetty!</h1>" +
102
"<p>Method: " + method + "</p>" +
103
"<p>Path: " + path + "</p></body></html>";
104
105
response.write(true, ByteBuffer.wrap(html.getBytes()), callback);
106
return true;
107
}
108
}
109
```
110
111
### Reading Request Content
112
113
```java
114
public class ContentHandler extends Handler.Abstract {
115
@Override
116
public boolean handle(Request request, Response response, Callback callback)
117
throws Exception {
118
119
// Check if request has content
120
String contentType = request.getHeaders().get("Content-Type");
121
if (contentType != null && contentType.startsWith("application/json")) {
122
readJsonContent(request, response, callback);
123
} else {
124
handleNoContent(response, callback);
125
}
126
127
return true;
128
}
129
130
private void readJsonContent(Request request, Response response, Callback callback) {
131
StringBuilder content = new StringBuilder();
132
133
// Read content chunks asynchronously
134
request.demand(() -> {
135
Content.Chunk chunk;
136
while ((chunk = request.read()) != null) {
137
if (chunk.hasRemaining()) {
138
// Process content chunk
139
ByteBuffer buffer = chunk.getByteBuffer();
140
byte[] bytes = new byte[buffer.remaining()];
141
buffer.get(bytes);
142
content.append(new String(bytes, StandardCharsets.UTF_8));
143
}
144
145
chunk.release();
146
147
if (chunk.isLast()) {
148
// All content read, process and respond
149
processJsonAndRespond(content.toString(), response, callback);
150
return;
151
}
152
}
153
154
// Need more content, demand again
155
request.demand(() -> readJsonContent(request, response, callback));
156
});
157
}
158
159
private void processJsonAndRespond(String json, Response response, Callback callback) {
160
response.setStatus(200);
161
response.getHeaders().put("Content-Type", "application/json");
162
163
String responseJson = "{\"received\": " + json + ", \"status\": \"processed\"}";
164
response.write(true, ByteBuffer.wrap(responseJson.getBytes()), callback);
165
}
166
167
private void handleNoContent(Response response, Callback callback) {
168
response.setStatus(400);
169
response.getHeaders().put("Content-Type", "text/plain");
170
response.write(true, ByteBuffer.wrap("No content provided".getBytes()), callback);
171
}
172
}
173
```
174
175
### Cookie and Session Handling
176
177
```java
178
public class SessionHandler extends Handler.Abstract {
179
@Override
180
public boolean handle(Request request, Response response, Callback callback)
181
throws Exception {
182
183
// Get or create session
184
Session session = request.getSession(true);
185
String sessionId = session.getId();
186
187
// Read session data
188
Integer visitCount = (Integer) session.getAttribute("visitCount");
189
if (visitCount == null) {
190
visitCount = 0;
191
}
192
visitCount++;
193
session.setAttribute("visitCount", visitCount);
194
195
// Read cookies
196
List<HttpCookie> cookies = request.getCookies();
197
String preferredLang = null;
198
for (HttpCookie cookie : cookies) {
199
if ("lang".equals(cookie.getName())) {
200
preferredLang = cookie.getValue();
201
break;
202
}
203
}
204
205
// Set response cookie
206
if (preferredLang == null) {
207
preferredLang = "en";
208
HttpCookie langCookie = HttpCookie.build("lang", preferredLang)
209
.path("/")
210
.maxAge(Duration.ofDays(30))
211
.httpOnly(true)
212
.build();
213
response.getHeaders().addCookie(langCookie);
214
}
215
216
// Generate response
217
response.setStatus(200);
218
response.getHeaders().put("Content-Type", "text/html");
219
220
String html = String.format(
221
"<html><body>" +
222
"<h1>Session Demo</h1>" +
223
"<p>Session ID: %s</p>" +
224
"<p>Visit count: %d</p>" +
225
"<p>Language: %s</p>" +
226
"</body></html>",
227
sessionId, visitCount, preferredLang);
228
229
response.write(true, ByteBuffer.wrap(html.getBytes()), callback);
230
return true;
231
}
232
}
233
```
234
235
## Content Processing
236
237
### FormFields
238
239
Parse form data from request content.
240
241
```java { .api }
242
public class FormFields extends ContentSourceCompletableFuture<Fields> {
243
public static CompletableFuture<Fields> from(Request request);
244
public static CompletableFuture<Fields> from(Request request, Charset charset, int maxFields, int maxLength);
245
}
246
```
247
248
Usage:
249
250
```java
251
public class FormHandler extends Handler.Abstract {
252
@Override
253
public boolean handle(Request request, Response response, Callback callback)
254
throws Exception {
255
256
String contentType = request.getHeaders().get("Content-Type");
257
if ("application/x-www-form-urlencoded".equals(contentType)) {
258
259
FormFields.from(request).thenAccept(fields -> {
260
// Process form fields
261
String name = fields.getValue("name");
262
String email = fields.getValue("email");
263
264
// Generate response
265
response.setStatus(200);
266
response.getHeaders().put("Content-Type", "text/plain");
267
String responseText = "Received: name=" + name + ", email=" + email;
268
response.write(true, ByteBuffer.wrap(responseText.getBytes()), callback);
269
270
}).exceptionally(throwable -> {
271
// Handle parsing error
272
response.setStatus(400);
273
response.getHeaders().put("Content-Type", "text/plain");
274
response.write(true, ByteBuffer.wrap("Invalid form data".getBytes()), callback);
275
return null;
276
});
277
278
return true;
279
}
280
281
return false; // Not handled
282
}
283
}
284
```
285
286
## HTTP URI Processing
287
288
### HttpURI Interface
289
290
```java { .api }
291
public interface HttpURI {
292
String getScheme();
293
String getHost();
294
int getPort();
295
String getPath();
296
String getQuery();
297
String getFragment();
298
String getParam(String key);
299
Map<String, List<String>> getQueryParameters();
300
boolean isAbsolute();
301
}
302
```
303
304
Usage:
305
306
```java
307
public boolean handle(Request request, Response response, Callback callback) throws Exception {
308
HttpURI uri = request.getHttpURI();
309
310
String scheme = uri.getScheme(); // "http" or "https"
311
String host = uri.getHost(); // "localhost"
312
int port = uri.getPort(); // 8080
313
String path = uri.getPath(); // "/api/users"
314
String query = uri.getQuery(); // "page=1&size=10"
315
316
// Parse query parameters
317
Map<String, List<String>> queryParams = uri.getQueryParameters();
318
String page = queryParams.containsKey("page") ?
319
queryParams.get("page").get(0) : "1";
320
String size = queryParams.containsKey("size") ?
321
queryParams.get("size").get(0) : "20";
322
323
// Generate response based on parameters
324
response.setStatus(200);
325
response.getHeaders().put("Content-Type", "application/json");
326
327
String json = String.format(
328
"{\"path\": \"%s\", \"page\": %s, \"size\": %s}",
329
path, page, size);
330
331
response.write(true, ByteBuffer.wrap(json.getBytes()), callback);
332
return true;
333
}
334
```
335
336
## Header Management
337
338
### HttpFields Interface
339
340
```java { .api }
341
public interface HttpFields extends Iterable<HttpField> {
342
// Field access
343
HttpField getField(String name);
344
String get(String name);
345
List<String> getValuesList(String name);
346
int size();
347
boolean contains(String name);
348
boolean contains(String name, String value);
349
350
// Iteration
351
Iterator<HttpField> iterator();
352
Stream<HttpField> stream();
353
354
// Mutable version for responses
355
interface Mutable extends HttpFields {
356
HttpField put(String name, String value);
357
HttpField add(String name, String value);
358
boolean remove(String name);
359
void clear();
360
void addCookie(HttpCookie cookie);
361
}
362
}
363
```
364
365
## Connection Metadata
366
367
### ConnectionMetaData Interface
368
369
```java { .api }
370
public interface ConnectionMetaData extends Attributes {
371
String getId();
372
HttpConfiguration getHttpConfiguration();
373
String getProtocol();
374
SocketAddress getLocalSocketAddress();
375
SocketAddress getRemoteSocketAddress();
376
boolean isSecure();
377
X509Certificate[] getPeerCertificates();
378
}
379
```
380
381
Usage:
382
383
```java
384
public boolean handle(Request request, Response response, Callback callback) throws Exception {
385
ConnectionMetaData connMeta = request.getConnectionMetaData();
386
387
String protocol = connMeta.getProtocol(); // "HTTP/1.1", "HTTP/2", etc.
388
boolean isSecure = connMeta.isSecure(); // true for HTTPS
389
SocketAddress remoteAddr = connMeta.getRemoteSocketAddress();
390
391
// Client certificate info for mutual TLS
392
X509Certificate[] clientCerts = connMeta.getPeerCertificates();
393
String clientDN = null;
394
if (clientCerts != null && clientCerts.length > 0) {
395
clientDN = clientCerts[0].getSubjectX500Principal().getName();
396
}
397
398
// Generate response with connection info
399
response.setStatus(200);
400
response.getHeaders().put("Content-Type", "application/json");
401
402
String json = String.format(
403
"{\"protocol\": \"%s\", \"secure\": %b, \"remote\": \"%s\", \"clientDN\": \"%s\"}",
404
protocol, isSecure, remoteAddr, clientDN);
405
406
response.write(true, ByteBuffer.wrap(json.getBytes()), callback);
407
return true;
408
}
409
```
410
411
## Request Wrappers
412
413
### Request.Wrapper
414
415
Base class for wrapping and modifying requests.
416
417
```java { .api }
418
public static class Request.Wrapper implements Request {
419
public Request getWrapped();
420
421
// All Request methods delegate to wrapped instance
422
// Override specific methods to modify behavior
423
}
424
```
425
426
Usage:
427
428
```java
429
public class TimingRequestWrapper extends Request.Wrapper {
430
private final long startTime;
431
432
public TimingRequestWrapper(Request wrapped) {
433
super(wrapped);
434
this.startTime = System.nanoTime();
435
}
436
437
public long getProcessingTime() {
438
return System.nanoTime() - startTime;
439
}
440
}
441
442
// In handler
443
TimingRequestWrapper timedRequest = new TimingRequestWrapper(request);
444
// Process request...
445
long processingTime = timedRequest.getProcessingTime();
446
```
447
448
## Response Wrappers
449
450
### Response.Wrapper
451
452
Base class for wrapping and modifying responses.
453
454
```java { .api }
455
public static class Response.Wrapper implements Response {
456
public Response getWrapped();
457
458
// Override methods to intercept/modify response behavior
459
}
460
```
461
462
Usage:
463
464
```java
465
public class CompressingResponseWrapper extends Response.Wrapper {
466
private final GZIPOutputStream gzipOut;
467
468
public CompressingResponseWrapper(Response wrapped) throws IOException {
469
super(wrapped);
470
this.gzipOut = new GZIPOutputStream(new ResponseOutputStream(wrapped));
471
}
472
473
@Override
474
public void write(boolean last, ByteBuffer content, Callback callback) {
475
try {
476
// Compress content before writing
477
byte[] bytes = new byte[content.remaining()];
478
content.get(bytes);
479
gzipOut.write(bytes);
480
481
if (last) {
482
gzipOut.close();
483
}
484
485
callback.succeeded();
486
} catch (IOException e) {
487
callback.failed(e);
488
}
489
}
490
}
491
```