@@ -73,6 +73,16 @@ public HttpServletResponse(HttpServletRequest request, jakarta.servlet.http.Http
73
73
}
74
74
75
75
76
+ //**************************************************************************
77
+ //** getRequest
78
+ //**************************************************************************
79
+ /** Returns the HttpServletRequest request used to initiate this response.
80
+ */
81
+ public HttpServletRequest getRequest (){
82
+ return request ;
83
+ }
84
+
85
+
76
86
//**************************************************************************
77
87
//** addCookie
78
88
//**************************************************************************
@@ -482,15 +492,17 @@ public void sendRedirect(String location, boolean movedPermanently)
482
492
//**************************************************************************
483
493
//** write
484
494
//**************************************************************************
485
- /** Used to write a block of text in the response body. You should only call
486
- * this method once.
495
+ /** Used to write text (plain text, html, json, etc) to the response body.
496
+ * You should only call this method once.
487
497
* @param compressOutput Specify whether to gzip compress the text.
488
498
* Note that this option will be applied only if "Accept-Encoding" supports
489
499
* gzip compression.
490
500
*/
491
501
public void write (String text , boolean compressOutput ) throws IOException {
492
502
try {
493
- write (text .getBytes (charSet ), compressOutput );
503
+ byte [] bytes = text .getBytes (charSet );
504
+ setCharacterEncoding (charSet );
505
+ write (bytes , compressOutput );
494
506
}
495
507
catch (java .io .UnsupportedEncodingException e ){
496
508
//this error should have been thrown earlier (setCharacterEncoding)
@@ -501,12 +513,27 @@ public void write(String text, boolean compressOutput) throws IOException {
501
513
//**************************************************************************
502
514
//** write
503
515
//**************************************************************************
504
- /** Used to write a block of text in the response body. Will automatically
505
- * try to gzip compress the text if "Accept-Encoding" supports gzip
506
- * compression. You should only call this method once.
516
+ /** Used to write text (plain text, html, json, etc) to the response body.
517
+ * Will automatically try to gzip compress the text if "Accept-Encoding"
518
+ * supports gzip compression. You should only call this method once.
507
519
*/
508
520
public void write (String text ) throws IOException {
509
- this .write (text , true );
521
+ write (text , true );
522
+ }
523
+
524
+
525
+ //**************************************************************************
526
+ //** write
527
+ //**************************************************************************
528
+ /** Used to write text (plain text, html, json, etc) to the response body.
529
+ * Transparently handles caching using "ETag" and "Last-Modified" headers.
530
+ * Will automatically try to gzip compress the text if "Accept-Encoding"
531
+ * supports gzip compression. You should only call this method once.
532
+ * @param date UTC date in milliseconds since January 1, 1970, 00:00:00 UTC
533
+ */
534
+ public void write (String text , long date ) throws IOException {
535
+ if (send304 (date , text .length ())) return ;
536
+ write (text , true );
510
537
}
511
538
512
539
@@ -657,6 +684,21 @@ public void write(byte[] bytes) throws IOException {
657
684
}
658
685
659
686
687
+ //**************************************************************************
688
+ //** write
689
+ //**************************************************************************
690
+ /** Used to write bytes to the response body. Transparently handles caching
691
+ * using "ETag" and "Last-Modified" headers. Will automatically try to gzip
692
+ * compress the text if "Accept-Encoding" supports gzip compression. You
693
+ * should only call this method once.
694
+ * @param date UTC date in milliseconds since January 1, 1970, 00:00:00 UTC
695
+ */
696
+ public void write (byte [] bytes , long date ) throws IOException {
697
+ if (send304 (date , bytes .length )) return ;
698
+ write (bytes , true );
699
+ }
700
+
701
+
660
702
//**************************************************************************
661
703
//** write
662
704
//**************************************************************************
@@ -682,14 +724,19 @@ public void write(java.io.File file, String contentType, boolean useCache)
682
724
/** Used to write contents of a file into the response body. Automatically
683
725
* compresses the file content if the client supports gzip compression.
684
726
* You should only call this method once.
685
- * @param fileName Optional file name used in the "Content-Disposition" header.
686
- * If the fileName is null, the "Content-Disposition" header will not be
687
- * set by this method.
727
+ * @param file The file to send to the client
728
+ * @param fileName Optional file name used in the "Content-Disposition"
729
+ * header. If the fileName is null, the "Content-Disposition" header will
730
+ * not be set by this method.
731
+ * @param useCache If true, will generate "ETag", "Last-Modified", and
732
+ * "Cache-Control" headers. If the "ETag" matches the "if-none-match"
733
+ * or if the "Last-Modified" matches the "if-modified-since" request
734
+ * headers then a 304 "Not Modified" is returned.
688
735
*/
689
736
public void write (java .io .File file , String fileName , String contentType , boolean useCache )
690
737
throws IOException {
691
738
692
- if (!file .exists () || file .isDirectory ()){
739
+ if (file == null || !file .exists () || file .isDirectory ()){
693
740
this .setStatus (404 );
694
741
return ;
695
742
}
@@ -700,44 +747,10 @@ public void write(java.io.File file, String fileName, String contentType, boolea
700
747
701
748
//Process Cache Directives
702
749
if (useCache ){
703
-
704
- String eTag = "W/\" " + fileSize + "-" + fileDate + "\" " ;
705
- setHeader ("ETag" , eTag );
706
- setHeader ("Last-Modified" , getDate (fileDate )); //Sat, 23 Oct 2010 13:04:28 GMT
707
- //this.setHeader("Cache-Control", "max-age=315360000");
708
- //this.setHeader("Expires", "Sun, 30 Sep 2018 16:23:15 GMT ");
709
-
710
-
711
- //Return 304/Not Modified response if we can...
712
- String matchTag = request .getHeader ("if-none-match" );
713
- String cacheControl = request .getHeader ("cache-control" );
714
- if (matchTag ==null ) matchTag = "" ;
715
- if (cacheControl ==null ) cacheControl = "" ;
716
- if (cacheControl .equalsIgnoreCase ("no-cache" )==false ){
717
- if (eTag .equalsIgnoreCase (matchTag )){
718
- //System.out.println("Sending 304 Response!");
719
- this .setStatus (304 );
720
- return ;
721
- }
722
- else{
723
- //Internet Explorer 6 uses "if-modified-since" instead of "if-none-match"
724
- matchTag = request .getHeader ("if-modified-since" );
725
- if (matchTag !=null ){
726
- for (String tag : matchTag .split (";" )){
727
- if (tag .trim ().equalsIgnoreCase (getDate (fileDate ))){
728
- //System.out.println("Sending 304 Response!");
729
- this .setStatus (304 );
730
- return ;
731
- }
732
- }
733
- }
734
-
735
- }
736
- }
737
-
750
+ if (send304 (fileDate , fileSize )) return ;
738
751
}
739
752
else {
740
- setHeader ("Cache-Control" , "no-cache " );
753
+ setHeader ("Cache-Control" , "no-store " );
741
754
}
742
755
743
756
@@ -1223,6 +1236,61 @@ private String getDate(long milliseconds){
1223
1236
}
1224
1237
1225
1238
1239
+ //**************************************************************************
1240
+ //** send304
1241
+ //**************************************************************************
1242
+ /** Sets the "ETag", "Last-Modified", and "Cache-Control" response headers.
1243
+ * If the "ETag" matches the "if-none-match" or if the "Last-Modified"
1244
+ * matches the "if-modified-since" request headers then the status is set
1245
+ * to 304 "Not Modified".
1246
+ * @return Returns true if the status was set to 304. Otherwise, returns
1247
+ * false.
1248
+ */
1249
+ private boolean send304 (long date , long size ){
1250
+
1251
+ //Generate "ETag", "Last-Modified" headers
1252
+ String eTag = "W/\" " + size + "-" + date + "\" " ;
1253
+ response .setHeader ("ETag" , eTag );
1254
+ response .setHeader ("Last-Modified" , getDate (date )); //Sat, 23 Oct 2010 13:04:28 GMT
1255
+
1256
+
1257
+ //Set "Cache-Control" to "no-cache". The no-cache response directive
1258
+ //indicates that the response can be stored in caches, but the response
1259
+ //must be validated with the server before each reuse.
1260
+ response .setHeader ("Cache-Control" , "no-cache" );
1261
+
1262
+
1263
+ //Return 304/Not Modified response if we can...
1264
+ String matchTag = request .getHeader ("if-none-match" );
1265
+ String cacheControl = request .getHeader ("cache-control" );
1266
+ if (matchTag ==null ) matchTag = "" ;
1267
+ if (cacheControl ==null ) cacheControl = "" ;
1268
+ if (cacheControl .equalsIgnoreCase ("no-cache" )==false ){
1269
+ if (eTag .equalsIgnoreCase (matchTag )){
1270
+ //System.out.println("Sending 304 Response!");
1271
+ response .setStatus (304 );
1272
+ return true ;
1273
+ }
1274
+ else {
1275
+ //Internet Explorer 6 uses "if-modified-since" instead of "if-none-match"
1276
+ matchTag = request .getHeader ("if-modified-since" );
1277
+ if (matchTag !=null ){
1278
+ for (String tag : matchTag .split (";" )){
1279
+ if (tag .trim ().equalsIgnoreCase (response .getHeader ("Last-Modified" ))){
1280
+ //System.out.println("Sending 304 Response!");
1281
+ response .setStatus (304 );
1282
+ return true ;
1283
+ }
1284
+ }
1285
+ }
1286
+
1287
+ }
1288
+ }
1289
+
1290
+ return false ;
1291
+ }
1292
+
1293
+
1226
1294
//**************************************************************************
1227
1295
//** reset
1228
1296
//**************************************************************************
0 commit comments