0
# HTTP Request and Response Processing
1
2
The Java Servlet API provides comprehensive support for HTTP request and response processing. This includes handling different HTTP methods, processing request parameters and headers, managing response output, and supporting advanced features like multipart requests and HTTP/2 server push.
3
4
## HttpServlet Base Class
5
6
```java { .api }
7
/**
8
* Abstract base class for HTTP servlets.
9
* Extends GenericServlet and provides HTTP-specific functionality.
10
*/
11
public abstract class HttpServlet extends GenericServlet {
12
13
/**
14
* Handle HTTP GET requests.
15
* Default implementation returns HTTP 405 (Method Not Allowed).
16
*/
17
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
18
throws ServletException, IOException {
19
String protocol = req.getProtocol();
20
String msg = lStrings.getString("http.method_get_not_supported");
21
if (protocol.endsWith("1.1")) {
22
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
23
} else {
24
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
25
}
26
}
27
28
/**
29
* Handle HTTP POST requests.
30
* Default implementation returns HTTP 405 (Method Not Allowed).
31
*/
32
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
33
throws ServletException, IOException {
34
String protocol = req.getProtocol();
35
String msg = lStrings.getString("http.method_post_not_supported");
36
if (protocol.endsWith("1.1")) {
37
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
38
} else {
39
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
40
}
41
}
42
43
/**
44
* Handle HTTP PUT requests.
45
* Default implementation returns HTTP 405 (Method Not Allowed).
46
*/
47
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
48
throws ServletException, IOException {
49
String protocol = req.getProtocol();
50
String msg = lStrings.getString("http.method_put_not_supported");
51
if (protocol.endsWith("1.1")) {
52
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
53
} else {
54
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
55
}
56
}
57
58
/**
59
* Handle HTTP DELETE requests.
60
* Default implementation returns HTTP 405 (Method Not Allowed).
61
*/
62
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
63
throws ServletException, IOException {
64
String protocol = req.getProtocol();
65
String msg = lStrings.getString("http.method_delete_not_supported");
66
if (protocol.endsWith("1.1")) {
67
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
68
} else {
69
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
70
}
71
}
72
73
/**
74
* Handle HTTP HEAD requests.
75
* Default implementation calls doGet and discards response body.
76
*/
77
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
78
throws ServletException, IOException {
79
NoBodyResponse response = new NoBodyResponse(resp);
80
doGet(req, response);
81
response.setContentLength();
82
}
83
84
/**
85
* Handle HTTP OPTIONS requests.
86
* Default implementation determines which methods are supported.
87
*/
88
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
89
throws ServletException, IOException {
90
91
Method[] methods = getAllDeclaredMethods(this.getClass());
92
boolean ALLOW_GET = false;
93
boolean ALLOW_HEAD = false;
94
boolean ALLOW_POST = false;
95
boolean ALLOW_PUT = false;
96
boolean ALLOW_DELETE = false;
97
boolean ALLOW_TRACE = true;
98
boolean ALLOW_OPTIONS = true;
99
100
// Check which doXXX methods are overridden
101
for (Method method : methods) {
102
if (method.getName().equals("doGet")) {
103
ALLOW_GET = true;
104
ALLOW_HEAD = true;
105
} else if (method.getName().equals("doPost")) {
106
ALLOW_POST = true;
107
} else if (method.getName().equals("doPut")) {
108
ALLOW_PUT = true;
109
} else if (method.getName().equals("doDelete")) {
110
ALLOW_DELETE = true;
111
}
112
}
113
114
StringBuilder allow = new StringBuilder();
115
if (ALLOW_GET) allow.append("GET");
116
if (ALLOW_HEAD) append(allow, "HEAD");
117
if (ALLOW_POST) append(allow, "POST");
118
if (ALLOW_PUT) append(allow, "PUT");
119
if (ALLOW_DELETE) append(allow, "DELETE");
120
if (ALLOW_TRACE) append(allow, "TRACE");
121
if (ALLOW_OPTIONS) append(allow, "OPTIONS");
122
123
resp.setHeader("Allow", allow.toString());
124
}
125
126
/**
127
* Handle HTTP TRACE requests.
128
* Default implementation reflects the request back as the response.
129
*/
130
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
131
throws ServletException, IOException {
132
133
String CRLF = "\r\n";
134
StringBuilder buffer = new StringBuilder("TRACE ")
135
.append(req.getRequestURI())
136
.append(" ")
137
.append(req.getProtocol())
138
.append(CRLF);
139
140
Enumeration<String> reqHeaderEnum = req.getHeaderNames();
141
while (reqHeaderEnum.hasMoreElements()) {
142
String headerName = reqHeaderEnum.nextElement();
143
buffer.append(headerName).append(": ")
144
.append(req.getHeader(headerName)).append(CRLF);
145
}
146
147
buffer.append(CRLF);
148
149
int responseLength = buffer.length();
150
resp.setContentType("message/http");
151
resp.setContentLength(responseLength);
152
ServletOutputStream out = resp.getOutputStream();
153
out.print(buffer.toString());
154
}
155
156
/**
157
* Get the last modified time for the resource.
158
* Default returns -1 (unknown).
159
*/
160
protected long getLastModified(HttpServletRequest req) {
161
return -1;
162
}
163
164
/**
165
* Dispatch HTTP requests to appropriate doXXX methods.
166
*/
167
@Override
168
public void service(ServletRequest req, ServletResponse res)
169
throws ServletException, IOException {
170
171
HttpServletRequest request;
172
HttpServletResponse response;
173
174
try {
175
request = (HttpServletRequest) req;
176
response = (HttpServletResponse) res;
177
} catch (ClassCastException e) {
178
throw new ServletException("Non-HTTP request or response");
179
}
180
181
service(request, response);
182
}
183
184
/**
185
* HTTP-specific service method that dispatches to doXXX methods.
186
*/
187
protected void service(HttpServletRequest req, HttpServletResponse resp)
188
throws ServletException, IOException {
189
190
String method = req.getMethod();
191
192
if (method.equals(METHOD_GET)) {
193
long lastModified = getLastModified(req);
194
if (lastModified == -1) {
195
doGet(req, resp);
196
} else {
197
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
198
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
199
maybeSetLastModified(resp, lastModified);
200
doGet(req, resp);
201
} else {
202
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
203
}
204
}
205
} else if (method.equals(METHOD_HEAD)) {
206
long lastModified = getLastModified(req);
207
maybeSetLastModified(resp, lastModified);
208
doHead(req, resp);
209
} else if (method.equals(METHOD_POST)) {
210
doPost(req, resp);
211
} else if (method.equals(METHOD_PUT)) {
212
doPut(req, resp);
213
} else if (method.equals(METHOD_DELETE)) {
214
doDelete(req, resp);
215
} else if (method.equals(METHOD_OPTIONS)) {
216
doOptions(req, resp);
217
} else if (method.equals(METHOD_TRACE)) {
218
doTrace(req, resp);
219
} else {
220
String errMsg = lStrings.getString("http.method_not_implemented");
221
Object[] errArgs = new Object[1];
222
errArgs[0] = method;
223
errMsg = MessageFormat.format(errMsg, errArgs);
224
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
225
}
226
}
227
}
228
```
229
230
## HttpServletRequest Interface
231
232
```java { .api }
233
/**
234
* HTTP-specific servlet request interface.
235
* Extends ServletRequest with HTTP-specific functionality.
236
*/
237
public interface HttpServletRequest extends ServletRequest {
238
239
// HTTP method constants
240
public static final String BASIC_AUTH = "BASIC";
241
public static final String FORM_AUTH = "FORM";
242
public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
243
public static final String DIGEST_AUTH = "DIGEST";
244
245
// Request attributes for authentication
246
public static final String AUTHORIZATION = "javax.servlet.http.authorization";
247
public static final String REMOTE_USER = "javax.servlet.http.remoteUser";
248
249
/**
250
* Get the authentication scheme (BASIC, FORM, etc.)
251
*/
252
String getAuthType();
253
254
/**
255
* Get all cookies sent with this request.
256
*/
257
Cookie[] getCookies();
258
259
/**
260
* Get the value of a date header.
261
*/
262
long getDateHeader(String name);
263
264
/**
265
* Get the value of a request header.
266
*/
267
String getHeader(String name);
268
269
/**
270
* Get all values for a header with multiple values.
271
*/
272
Enumeration<String> getHeaders(String name);
273
274
/**
275
* Get all header names in this request.
276
*/
277
Enumeration<String> getHeaderNames();
278
279
/**
280
* Get the value of an integer header.
281
*/
282
int getIntHeader(String name);
283
284
/**
285
* Get servlet mapping information for this request.
286
*/
287
HttpServletMapping getHttpServletMapping();
288
289
/**
290
* Get the HTTP method (GET, POST, etc.)
291
*/
292
String getMethod();
293
294
/**
295
* Get extra path information after servlet path.
296
*/
297
String getPathInfo();
298
299
/**
300
* Get real path corresponding to path info.
301
*/
302
String getPathTranslated();
303
304
/**
305
* Get the context path portion of the request URL.
306
*/
307
String getContextPath();
308
309
/**
310
* Get the query string from the request URL.
311
*/
312
String getQueryString();
313
314
/**
315
* Get the login name of the authenticated user.
316
*/
317
String getRemoteUser();
318
319
/**
320
* Check if the user is in the specified role.
321
*/
322
boolean isUserInRole(String role);
323
324
/**
325
* Get the Principal object for the authenticated user.
326
*/
327
java.security.Principal getUserPrincipal();
328
329
/**
330
* Get the session ID from the request.
331
*/
332
String getRequestedSessionId();
333
334
/**
335
* Get the full request URI.
336
*/
337
String getRequestURI();
338
339
/**
340
* Get the full request URL including query string.
341
*/
342
StringBuffer getRequestURL();
343
344
/**
345
* Get the servlet path portion of the request URL.
346
*/
347
String getServletPath();
348
349
/**
350
* Get the current session, creating one if necessary.
351
*/
352
HttpSession getSession(boolean create);
353
354
/**
355
* Get the current session (create = true).
356
*/
357
HttpSession getSession();
358
359
/**
360
* Change the session ID and return the new ID.
361
*/
362
String changeSessionId();
363
364
/**
365
* Check if the session ID came from a cookie.
366
*/
367
boolean isRequestedSessionIdValid();
368
369
/**
370
* Check if the session ID is still valid.
371
*/
372
boolean isRequestedSessionIdFromCookie();
373
374
/**
375
* Check if the session ID came from URL encoding.
376
*/
377
boolean isRequestedSessionIdFromURL();
378
379
/**
380
* Check if the session ID came from URL encoding (deprecated).
381
*/
382
@Deprecated
383
boolean isRequestedSessionIdFromUrl();
384
385
/**
386
* Programmatically authenticate the user.
387
*/
388
boolean authenticate(HttpServletResponse response)
389
throws IOException, ServletException;
390
391
/**
392
* Programmatically log in the user.
393
*/
394
void login(String username, String password) throws ServletException;
395
396
/**
397
* Programmatically log out the user.
398
*/
399
void logout() throws ServletException;
400
401
/**
402
* Get all parts from a multipart/form-data request.
403
*/
404
Collection<Part> getParts() throws IOException, ServletException;
405
406
/**
407
* Get a specific part by name from a multipart request.
408
*/
409
Part getPart(String name) throws IOException, ServletException;
410
411
/**
412
* Create an HttpUpgradeHandler for protocol upgrade.
413
*/
414
<T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)
415
throws IOException, ServletException;
416
}
417
```
418
419
## HttpServletResponse Interface
420
421
```java { .api }
422
/**
423
* HTTP-specific servlet response interface.
424
* Extends ServletResponse with HTTP-specific functionality.
425
*/
426
public interface HttpServletResponse extends ServletResponse {
427
428
// Status code constants
429
public static final int SC_CONTINUE = 100;
430
public static final int SC_SWITCHING_PROTOCOLS = 101;
431
public static final int SC_OK = 200;
432
public static final int SC_CREATED = 201;
433
public static final int SC_ACCEPTED = 202;
434
public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
435
public static final int SC_NO_CONTENT = 204;
436
public static final int SC_RESET_CONTENT = 205;
437
public static final int SC_PARTIAL_CONTENT = 206;
438
public static final int SC_MULTIPLE_CHOICES = 300;
439
public static final int SC_MOVED_PERMANENTLY = 301;
440
public static final int SC_MOVED_TEMPORARILY = 302;
441
public static final int SC_FOUND = 302;
442
public static final int SC_SEE_OTHER = 303;
443
public static final int SC_NOT_MODIFIED = 304;
444
public static final int SC_USE_PROXY = 305;
445
public static final int SC_TEMPORARY_REDIRECT = 307;
446
public static final int SC_BAD_REQUEST = 400;
447
public static final int SC_UNAUTHORIZED = 401;
448
public static final int SC_PAYMENT_REQUIRED = 402;
449
public static final int SC_FORBIDDEN = 403;
450
public static final int SC_NOT_FOUND = 404;
451
public static final int SC_METHOD_NOT_ALLOWED = 405;
452
public static final int SC_NOT_ACCEPTABLE = 406;
453
public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
454
public static final int SC_REQUEST_TIMEOUT = 408;
455
public static final int SC_CONFLICT = 409;
456
public static final int SC_GONE = 410;
457
public static final int SC_LENGTH_REQUIRED = 411;
458
public static final int SC_PRECONDITION_FAILED = 412;
459
public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
460
public static final int SC_REQUEST_URI_TOO_LONG = 414;
461
public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
462
public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
463
public static final int SC_EXPECTATION_FAILED = 417;
464
public static final int SC_INTERNAL_SERVER_ERROR = 500;
465
public static final int SC_NOT_IMPLEMENTED = 501;
466
public static final int SC_BAD_GATEWAY = 502;
467
public static final int SC_SERVICE_UNAVAILABLE = 503;
468
public static final int SC_GATEWAY_TIMEOUT = 504;
469
public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
470
471
/**
472
* Add a cookie to the response.
473
*/
474
void addCookie(Cookie cookie);
475
476
/**
477
* Check if the response contains the specified header.
478
*/
479
boolean containsHeader(String name);
480
481
/**
482
* Encode a URL for session tracking via URL rewriting.
483
*/
484
String encodeURL(String url);
485
486
/**
487
* Encode a redirect URL for session tracking.
488
*/
489
String encodeRedirectURL(String url);
490
491
/**
492
* Encode a URL for session tracking (deprecated).
493
*/
494
@Deprecated
495
String encodeUrl(String url);
496
497
/**
498
* Encode a redirect URL for session tracking (deprecated).
499
*/
500
@Deprecated
501
String encodeRedirectUrl(String url);
502
503
/**
504
* Send an error response with the specified status code.
505
*/
506
void sendError(int sc, String msg) throws IOException;
507
508
/**
509
* Send an error response with the specified status code.
510
*/
511
void sendError(int sc) throws IOException;
512
513
/**
514
* Send a redirect response to the specified URL.
515
*/
516
void sendRedirect(String location) throws IOException;
517
518
/**
519
* Set a date header with the given value.
520
*/
521
void setDateHeader(String name, long date);
522
523
/**
524
* Add a date header with the given value.
525
*/
526
void addDateHeader(String name, long date);
527
528
/**
529
* Set a header with the given value.
530
*/
531
void setHeader(String name, String value);
532
533
/**
534
* Add a header with the given value.
535
*/
536
void addHeader(String name, String value);
537
538
/**
539
* Set an integer header with the given value.
540
*/
541
void setIntHeader(String name, int value);
542
543
/**
544
* Add an integer header with the given value.
545
*/
546
void addIntHeader(String name, int value);
547
548
/**
549
* Set the response status code.
550
*/
551
void setStatus(int sc);
552
553
/**
554
* Set the response status code with message (deprecated).
555
*/
556
@Deprecated
557
void setStatus(int sc, String sm);
558
559
/**
560
* Get the response status code.
561
*/
562
int getStatus();
563
564
/**
565
* Get the value of a response header.
566
*/
567
String getHeader(String name);
568
569
/**
570
* Get all values for a response header.
571
*/
572
Collection<String> getHeaders(String name);
573
574
/**
575
* Get all response header names.
576
*/
577
Collection<String> getHeaderNames();
578
579
/**
580
* Get trailer fields for chunked encoding.
581
*/
582
Supplier<Map<String, String>> getTrailerFields();
583
584
/**
585
* Set trailer fields for chunked encoding.
586
*/
587
void setTrailerFields(Supplier<Map<String, String>> supplier);
588
}
589
```
590
591
## Multipart Request Processing
592
593
### Part Interface
594
595
```java { .api }
596
/**
597
* Interface representing a part in a multipart/form-data request.
598
*/
599
public interface Part {
600
601
/**
602
* Get an InputStream for reading the part content.
603
*/
604
InputStream getInputStream() throws IOException;
605
606
/**
607
* Get the content type of this part.
608
*/
609
String getContentType();
610
611
/**
612
* Get the name of this part (from the name attribute).
613
*/
614
String getName();
615
616
/**
617
* Get the submitted filename (from filename attribute).
618
*/
619
String getSubmittedFileName();
620
621
/**
622
* Get the size of this part in bytes.
623
*/
624
long getSize();
625
626
/**
627
* Write this part to a file on disk.
628
*/
629
void write(String fileName) throws IOException;
630
631
/**
632
* Delete any temporary storage for this part.
633
*/
634
void delete() throws IOException;
635
636
/**
637
* Get the value of a header for this part.
638
*/
639
String getHeader(String name);
640
641
/**
642
* Get all values for a header.
643
*/
644
Collection<String> getHeaders(String name);
645
646
/**
647
* Get all header names for this part.
648
*/
649
Collection<String> getHeaderNames();
650
}
651
```
652
653
### Multipart Configuration Examples
654
655
```java { .api }
656
/**
657
* Servlet configured for multipart request handling
658
*/
659
@WebServlet("/upload")
660
@MultipartConfig(
661
location = "/tmp",
662
fileSizeThreshold = 1024 * 1024, // 1 MB
663
maxFileSize = 1024 * 1024 * 5, // 5 MB
664
maxRequestSize = 1024 * 1024 * 5 * 5 // 25 MB
665
)
666
public class FileUploadServlet extends HttpServlet {
667
668
@Override
669
protected void doPost(HttpServletRequest request, HttpServletResponse response)
670
throws ServletException, IOException {
671
672
// Process regular form parameters
673
String description = request.getParameter("description");
674
675
// Process uploaded files
676
for (Part part : request.getParts()) {
677
if (part.getName().equals("file") && part.getSize() > 0) {
678
String fileName = getSubmittedFileName(part);
679
680
// Validate file type
681
String contentType = part.getContentType();
682
if (!isValidContentType(contentType)) {
683
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
684
"Invalid file type: " + contentType);
685
return;
686
}
687
688
// Save the file
689
String uploadPath = getServletContext().getRealPath("/uploads");
690
File uploadDir = new File(uploadPath);
691
if (!uploadDir.exists()) {
692
uploadDir.mkdirs();
693
}
694
695
String filePath = uploadPath + File.separator + fileName;
696
part.write(filePath);
697
698
// Log the upload
699
log("File uploaded: " + fileName + " (" + part.getSize() + " bytes)");
700
}
701
}
702
703
response.setContentType("application/json");
704
response.getWriter().write("{\"status\":\"success\",\"message\":\"Files uploaded\"}");
705
}
706
707
private String getSubmittedFileName(Part part) {
708
String contentDisposition = part.getHeader("Content-Disposition");
709
String[] elements = contentDisposition.split(";");
710
711
for (String element : elements) {
712
if (element.trim().startsWith("filename")) {
713
return element.substring(element.indexOf('=') + 1)
714
.trim().replace("\"", "");
715
}
716
}
717
return "unknown";
718
}
719
720
private boolean isValidContentType(String contentType) {
721
return contentType != null && (
722
contentType.startsWith("image/") ||
723
contentType.equals("application/pdf") ||
724
contentType.startsWith("text/")
725
);
726
}
727
}
728
```
729
730
## HTTP/2 Server Push Support
731
732
### PushBuilder Interface
733
734
```java { .api }
735
/**
736
* Interface for HTTP/2 server push functionality.
737
*/
738
public interface PushBuilder {
739
740
/**
741
* Set the HTTP method for the push request.
742
*/
743
PushBuilder method(String method);
744
745
/**
746
* Set the query string for the push request.
747
*/
748
PushBuilder queryString(String queryString);
749
750
/**
751
* Set the session ID for the push request.
752
*/
753
PushBuilder sessionId(String sessionId);
754
755
/**
756
* Set a header for the push request.
757
*/
758
PushBuilder setHeader(String name, String value);
759
760
/**
761
* Add a header to the push request.
762
*/
763
PushBuilder addHeader(String name, String value);
764
765
/**
766
* Remove a header from the push request.
767
*/
768
PushBuilder removeHeader(String name);
769
770
/**
771
* Set the path for the push request.
772
*/
773
PushBuilder path(String path);
774
775
/**
776
* Initiate the server push.
777
*/
778
void push();
779
780
/**
781
* Get the HTTP method for the push request.
782
*/
783
String getMethod();
784
785
/**
786
* Get the query string for the push request.
787
*/
788
String getQueryString();
789
790
/**
791
* Get the session ID for the push request.
792
*/
793
String getSessionId();
794
795
/**
796
* Get all header names for the push request.
797
*/
798
Set<String> getHeaderNames();
799
800
/**
801
* Get the value of a header for the push request.
802
*/
803
String getHeader(String name);
804
805
/**
806
* Get the path for the push request.
807
*/
808
String getPath();
809
}
810
```
811
812
### Server Push Example
813
814
```java { .api }
815
/**
816
* Servlet demonstrating HTTP/2 server push
817
*/
818
public class ServerPushServlet extends HttpServlet {
819
820
@Override
821
protected void doGet(HttpServletRequest request, HttpServletResponse response)
822
throws ServletException, IOException {
823
824
// Check if server push is supported
825
PushBuilder pushBuilder = request.newPushBuilder();
826
if (pushBuilder != null) {
827
// Push CSS resources
828
pushBuilder.path("/css/styles.css")
829
.setHeader("Content-Type", "text/css")
830
.push();
831
832
// Push JavaScript resources
833
pushBuilder.path("/js/app.js")
834
.setHeader("Content-Type", "application/javascript")
835
.push();
836
837
// Push image resources
838
pushBuilder.path("/images/logo.png")
839
.setHeader("Content-Type", "image/png")
840
.push();
841
}
842
843
// Generate the main HTML response
844
response.setContentType("text/html;charset=UTF-8");
845
PrintWriter out = response.getWriter();
846
847
out.println("<!DOCTYPE html>");
848
out.println("<html>");
849
out.println("<head>");
850
out.println(" <title>Server Push Example</title>");
851
out.println(" <link rel=\"stylesheet\" href=\"/css/styles.css\">");
852
out.println("</head>");
853
out.println("<body>");
854
out.println(" <img src=\"/images/logo.png\" alt=\"Logo\">");
855
out.println(" <h1>Welcome to Server Push Demo</h1>");
856
out.println(" <script src=\"/js/app.js\"></script>");
857
out.println("</body>");
858
out.println("</html>");
859
}
860
}
861
```
862
863
## Request and Response Wrapper Classes
864
865
```java { .api }
866
/**
867
* HTTP servlet request wrapper for request modification/decoration.
868
*/
869
public class HttpServletRequestWrapper extends ServletRequestWrapper
870
implements HttpServletRequest {
871
872
private HttpServletRequest request;
873
874
public HttpServletRequestWrapper(HttpServletRequest request) {
875
super(request);
876
if (request == null) {
877
throw new IllegalArgumentException("Request cannot be null");
878
}
879
this.request = request;
880
}
881
882
// Delegate all methods to wrapped request
883
public String getAuthType() {
884
return this.request.getAuthType();
885
}
886
887
public Cookie[] getCookies() {
888
return this.request.getCookies();
889
}
890
891
public long getDateHeader(String name) {
892
return this.request.getDateHeader(name);
893
}
894
895
public String getHeader(String name) {
896
return this.request.getHeader(name);
897
}
898
899
// ... all other HttpServletRequest methods
900
}
901
902
/**
903
* HTTP servlet response wrapper for response modification/decoration.
904
*/
905
public class HttpServletResponseWrapper extends ServletResponseWrapper
906
implements HttpServletResponse {
907
908
private HttpServletResponse response;
909
910
public HttpServletResponseWrapper(HttpServletResponse response) {
911
super(response);
912
if (response == null) {
913
throw new IllegalArgumentException("Response cannot be null");
914
}
915
this.response = response;
916
}
917
918
// Delegate all methods to wrapped response
919
public void addCookie(Cookie cookie) {
920
this.response.addCookie(cookie);
921
}
922
923
public boolean containsHeader(String name) {
924
return this.response.containsHeader(name);
925
}
926
927
public String encodeURL(String url) {
928
return this.response.encodeURL(url);
929
}
930
931
// ... all other HttpServletResponse methods
932
}
933
```
934
935
## Content Processing Examples
936
937
### JSON API Servlet
938
939
```java { .api }
940
/**
941
* REST API servlet for JSON processing
942
*/
943
@WebServlet("/api/users/*")
944
public class UserAPIServlet extends HttpServlet {
945
946
private final ObjectMapper mapper = new ObjectMapper();
947
948
@Override
949
protected void doGet(HttpServletRequest request, HttpServletResponse response)
950
throws ServletException, IOException {
951
952
String pathInfo = request.getPathInfo();
953
response.setContentType("application/json;charset=UTF-8");
954
955
try {
956
if (pathInfo == null || pathInfo.equals("/")) {
957
// Get all users
958
List<User> users = getUserService().getAllUsers();
959
writeJsonResponse(response, users);
960
} else {
961
// Get specific user
962
String userId = pathInfo.substring(1);
963
User user = getUserService().getUser(userId);
964
if (user != null) {
965
writeJsonResponse(response, user);
966
} else {
967
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
968
writeJsonResponse(response, Map.of("error", "User not found"));
969
}
970
}
971
} catch (Exception e) {
972
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
973
writeJsonResponse(response, Map.of("error", "Internal server error"));
974
}
975
}
976
977
@Override
978
protected void doPost(HttpServletRequest request, HttpServletResponse response)
979
throws ServletException, IOException {
980
981
response.setContentType("application/json;charset=UTF-8");
982
983
try {
984
// Read JSON request body
985
User user = mapper.readValue(request.getInputStream(), User.class);
986
987
// Validate user data
988
if (user.getName() == null || user.getEmail() == null) {
989
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
990
writeJsonResponse(response, Map.of("error", "Name and email are required"));
991
return;
992
}
993
994
// Create user
995
User createdUser = getUserService().createUser(user);
996
response.setStatus(HttpServletResponse.SC_CREATED);
997
writeJsonResponse(response, createdUser);
998
999
} catch (JsonProcessingException e) {
1000
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
1001
writeJsonResponse(response, Map.of("error", "Invalid JSON"));
1002
} catch (Exception e) {
1003
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
1004
writeJsonResponse(response, Map.of("error", "Internal server error"));
1005
}
1006
}
1007
1008
@Override
1009
protected void doPut(HttpServletRequest request, HttpServletResponse response)
1010
throws ServletException, IOException {
1011
1012
String pathInfo = request.getPathInfo();
1013
if (pathInfo == null || pathInfo.equals("/")) {
1014
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
1015
return;
1016
}
1017
1018
response.setContentType("application/json;charset=UTF-8");
1019
1020
try {
1021
String userId = pathInfo.substring(1);
1022
User user = mapper.readValue(request.getInputStream(), User.class);
1023
user.setId(userId);
1024
1025
User updatedUser = getUserService().updateUser(user);
1026
if (updatedUser != null) {
1027
writeJsonResponse(response, updatedUser);
1028
} else {
1029
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
1030
writeJsonResponse(response, Map.of("error", "User not found"));
1031
}
1032
} catch (Exception e) {
1033
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
1034
writeJsonResponse(response, Map.of("error", "Internal server error"));
1035
}
1036
}
1037
1038
@Override
1039
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
1040
throws ServletException, IOException {
1041
1042
String pathInfo = request.getPathInfo();
1043
if (pathInfo == null || pathInfo.equals("/")) {
1044
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
1045
return;
1046
}
1047
1048
response.setContentType("application/json;charset=UTF-8");
1049
1050
try {
1051
String userId = pathInfo.substring(1);
1052
boolean deleted = getUserService().deleteUser(userId);
1053
1054
if (deleted) {
1055
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
1056
} else {
1057
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
1058
writeJsonResponse(response, Map.of("error", "User not found"));
1059
}
1060
} catch (Exception e) {
1061
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
1062
writeJsonResponse(response, Map.of("error", "Internal server error"));
1063
}
1064
}
1065
1066
private void writeJsonResponse(HttpServletResponse response, Object data)
1067
throws IOException {
1068
PrintWriter writer = response.getWriter();
1069
mapper.writeValue(writer, data);
1070
writer.flush();
1071
}
1072
}
1073
```
1074
1075
This comprehensive coverage of HTTP request and response processing provides all the tools needed for handling HTTP communications in servlet applications, from basic request processing to advanced features like multipart uploads and HTTP/2 server push.