1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 package HTTPClient;
38
39 import java.io.InputStream;
40 import java.io.SequenceInputStream;
41 import java.io.ByteArrayInputStream;
42 import java.io.IOException;
43 import java.io.InterruptedIOException;
44 import java.io.EOFException;
45 import java.io.UnsupportedEncodingException;
46 import java.net.URL;
47 import java.net.ProtocolException;
48 import java.util.Date;
49 import java.util.Vector;
50 import java.util.Hashtable;
51 import java.util.StringTokenizer;
52 import java.util.NoSuchElementException;
53
54
55
56
57
58
59
60
61
62
63 public final class Response implements RoResponse, GlobalConstants, Cloneable
64 {
65
66 private static final Hashtable singleValueHeaders;
67
68
69 private HTTPConnection connection;
70
71
72 private StreamDemultiplexor stream_handler;
73
74
75 HTTPResponse http_resp;
76
77
78 int timeout = 0;
79
80
81
82 public InputStream inp_stream;
83
84
85 private RespInputStream resp_inp_stream = null;
86
87
88 private String method;
89
90
91 String resource;
92
93
94 private boolean used_proxy;
95
96
97 private boolean sent_entity;
98
99
100 int StatusCode = 0;
101
102
103 String ReasonLine;
104
105
106 String Version;
107
108
109 URI EffectiveURI = null;
110
111
112 CIHashtable Headers = new CIHashtable();
113
114
115 CIHashtable Trailers = new CIHashtable();
116
117
118
119
120 int ContentLength = -1;
121
122
123 int cd_type = CD_HDRS;
124
125
126 byte[] Data = null;
127
128
129 boolean reading_headers = false;
130
131
132 boolean got_headers = false;
133
134
135 boolean got_trailers = false;
136
137
138 private IOException exception = null;
139
140
141 boolean final_resp = false;
142
143
144 boolean retry = false;
145
146
147 static
148 {
149
150
151
152
153
154
155 String[] singleValueHeaderNames = {
156 "age", "location", "content-base", "content-length",
157 "content-location", "content-md5", "content-range", "content-type",
158 "date", "etag", "expires", "proxy-authenticate", "retry-after",
159 };
160
161 singleValueHeaders = new Hashtable(singleValueHeaderNames.length);
162 for (int idx=0; idx<singleValueHeaderNames.length; idx++)
163 singleValueHeaders.put(singleValueHeaderNames[idx],
164 singleValueHeaderNames[idx]);
165 }
166
167
168
169
170
171
172
173 Response(Request request, boolean used_proxy,
174 StreamDemultiplexor stream_handler)
175 throws IOException
176 {
177 this.connection = request.getConnection();
178 this.method = request.getMethod();
179 this.resource = request.getRequestURI();
180 this.used_proxy = used_proxy;
181 this.stream_handler = stream_handler;
182 sent_entity = (request.getData() != null) ? true : false;
183
184 stream_handler.register(this, request);
185 resp_inp_stream = stream_handler.getStream(this);
186 inp_stream = resp_inp_stream;
187 }
188
189
190
191
192
193
194
195
196
197
198
199 Response(Request request, InputStream is) throws IOException
200 {
201 this.connection = request.getConnection();
202 this.method = request.getMethod();
203 this.resource = request.getRequestURI();
204 used_proxy = false;
205 stream_handler = null;
206 sent_entity = (request.getData() != null) ? true : false;
207 inp_stream = is;
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228 public Response(String version, int status, String reason, NVPair[] headers,
229 byte[] data, InputStream is, int cont_len)
230 {
231 this.Version = version;
232 this.StatusCode = status;
233 this.ReasonLine = reason;
234 if (headers != null)
235 for (int idx=0; idx<headers.length; idx++)
236 setHeader(headers[idx].getName(), headers[idx].getValue());
237 if (data != null)
238 this.Data = data;
239 else if (is == null)
240 this.Data = new byte[0];
241 else
242 {
243 this.inp_stream = is;
244 ContentLength = cont_len;
245 }
246
247 got_headers = true;
248 got_trailers = true;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266 public final int getStatusCode() throws IOException
267 {
268 if (!got_headers) getHeaders(true);
269 return StatusCode;
270 }
271
272
273
274
275
276
277 public final String getReasonLine() throws IOException
278 {
279 if (!got_headers) getHeaders(true);
280 return ReasonLine;
281 }
282
283
284
285
286
287
288 public final String getVersion() throws IOException
289 {
290 if (!got_headers) getHeaders(true);
291 return Version;
292 }
293
294
295
296
297
298
299 int getContinue() throws IOException
300 {
301 getHeaders(false);
302 return StatusCode;
303 }
304
305
306
307
308
309
310
311
312
313 public final URI getEffectiveURI() throws IOException
314 {
315 if (!got_headers) getHeaders(true);
316 return EffectiveURI;
317 }
318
319
320
321
322 public void setEffectiveURI(URI final_uri)
323 {
324 EffectiveURI = final_uri;
325 }
326
327
328
329
330
331
332
333
334
335
336 public final URL getEffectiveURL() throws IOException
337 {
338 return getEffectiveURI().toURL();
339 }
340
341
342
343
344
345
346
347 public void setEffectiveURL(URL final_url)
348 {
349 try
350 { setEffectiveURI(new URI(final_url)); }
351 catch (ParseException pe)
352 { throw new Error(pe.toString()); }
353 }
354
355
356
357
358
359
360
361
362 public String getHeader(String hdr) throws IOException
363 {
364 if (!got_headers) getHeaders(true);
365 return (String) Headers.get(hdr.trim());
366 }
367
368
369
370
371
372
373
374
375
376
377
378 public int getHeaderAsInt(String hdr)
379 throws IOException, NumberFormatException
380 {
381 String val = getHeader(hdr);
382 if (val == null)
383 throw new NumberFormatException("null");
384 return Integer.parseInt(val);
385 }
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401 public Date getHeaderAsDate(String hdr)
402 throws IOException, IllegalArgumentException
403 {
404 String raw_date = getHeader(hdr);
405 if (raw_date == null) return null;
406
407
408 if (raw_date.toUpperCase().indexOf("GMT") == -1 &&
409 raw_date.indexOf(' ') > 0)
410 raw_date += " GMT";
411
412 Date date;
413
414 try
415 { date = Util.parseHttpDate(raw_date); }
416 catch (IllegalArgumentException iae)
417 {
418 long time;
419 try
420 { time = Long.parseLong(raw_date); }
421 catch (NumberFormatException nfe)
422 { throw iae; }
423 if (time < 0) time = 0;
424 date = new Date(time * 1000L);
425 }
426
427 return date;
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441 public void setHeader(String header, String value)
442 {
443 Headers.put(header.trim(), value.trim());
444 }
445
446
447
448
449
450
451
452
453
454 public void deleteHeader(String header)
455 {
456 Headers.remove(header.trim());
457 }
458
459
460
461
462
463
464
465
466
467
468
469 public String getTrailer(String trailer) throws IOException
470 {
471 if (!got_trailers) getTrailers();
472 return (String) Trailers.get(trailer.trim());
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486 public int getTrailerAsInt(String trailer)
487 throws IOException, NumberFormatException
488 {
489 String val = getTrailer(trailer);
490 if (val == null)
491 throw new NumberFormatException("null");
492 return Integer.parseInt(val);
493 }
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 public Date getTrailerAsDate(String trailer)
513 throws IOException, IllegalArgumentException
514 {
515 String raw_date = getTrailer(trailer);
516 if (raw_date == null) return null;
517
518
519 if (raw_date.toUpperCase().indexOf("GMT") == -1 &&
520 raw_date.indexOf(' ') > 0)
521 raw_date += " GMT";
522
523 Date date;
524
525 try
526 { date = Util.parseHttpDate(raw_date); }
527 catch (IllegalArgumentException iae)
528 {
529
530 long time;
531 try
532 { time = Long.parseLong(raw_date); }
533 catch (NumberFormatException nfe)
534 { throw iae; }
535 if (time < 0) time = 0;
536 date = new Date(time * 1000L);
537 }
538
539 return date;
540 }
541
542
543
544
545
546
547
548
549
550
551
552
553 public void setTrailer(String trailer, String value)
554 {
555 Trailers.put(trailer.trim(), value.trim());
556 }
557
558
559
560
561
562
563
564
565
566 public void deleteTrailer(String trailer)
567 {
568 Trailers.remove(trailer.trim());
569 }
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586 public synchronized byte[] getData() throws IOException
587 {
588 if (!got_headers) getHeaders(true);
589
590 if (Data == null)
591 {
592 try
593 { readResponseData(inp_stream); }
594 catch (InterruptedIOException ie)
595 { throw ie; }
596 catch (IOException ioe)
597 {
598 Log.write(Log.RESP, "Resp: (" + inp_stream.hashCode() + ")",
599 ioe);
600
601 try { inp_stream.close(); } catch (Exception e) { }
602 throw ioe;
603 }
604
605 inp_stream.close();
606 }
607
608 return Data;
609 }
610
611
612
613
614
615
616
617
618
619
620 public synchronized InputStream getInputStream() throws IOException
621 {
622 if (!got_headers) getHeaders(true);
623
624 if (Data == null)
625 return inp_stream;
626 else
627 return new ByteArrayInputStream(Data);
628 }
629
630
631
632
633
634
635
636
637
638
639
640 public synchronized boolean hasEntity() throws IOException
641 {
642 if (!got_headers) getHeaders(true);
643
644 return (cd_type != CD_0);
645 }
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661 public void setRetryRequest(boolean flag)
662 {
663 retry = flag;
664 }
665
666
667
668
669 public boolean retryRequest()
670 {
671 return retry;
672 }
673
674
675
676
677
678
679
680
681
682
683 private synchronized void getHeaders(boolean skip_cont) throws IOException
684 {
685 if (got_headers) return;
686 if (exception != null)
687 {
688 exception.fillInStackTrace();
689 throw exception;
690 }
691
692 reading_headers = true;
693 try
694 {
695 do
696 {
697 Headers.clear();
698 String headers = readResponseHeaders(inp_stream);
699 parseResponseHeaders(headers);
700 } while ((StatusCode == 100 && skip_cont) ||
701 (StatusCode > 101 && StatusCode < 200));
702 }
703 catch (IOException ioe)
704 {
705 if (!(ioe instanceof InterruptedIOException))
706 exception = ioe;
707 if (ioe instanceof ProtocolException)
708 {
709 cd_type = CD_CLOSE;
710 if (stream_handler != null)
711 stream_handler.markForClose(this);
712 }
713 throw ioe;
714 }
715 finally
716 { reading_headers = false; }
717 if (StatusCode == 100) return;
718
719
720
721
722 int cont_len = -1;
723 String cl_hdr = (String) Headers.get("Content-Length");
724 if (cl_hdr != null)
725 {
726 try
727 {
728 cont_len = Integer.parseInt(cl_hdr);
729 if (cont_len < 0)
730 throw new NumberFormatException();
731 }
732 catch (NumberFormatException nfe)
733 {
734 throw new ProtocolException("Invalid Content-length header"+
735 " received: "+cl_hdr);
736 }
737 }
738
739
740
741
742 boolean te_chunked = false, te_is_identity = true, ct_mpbr = false;
743 Vector te_hdr = null;
744 try
745 { te_hdr = Util.parseHeader((String) Headers.get("Transfer-Encoding")); }
746 catch (ParseException pe)
747 { }
748 if (te_hdr != null)
749 {
750 te_chunked = ((HttpHeaderElement) te_hdr.lastElement()).getName().
751 equalsIgnoreCase("chunked");
752 for (int idx=0; idx<te_hdr.size(); idx++)
753 if (((HttpHeaderElement) te_hdr.elementAt(idx)).getName().
754 equalsIgnoreCase("identity"))
755 te_hdr.removeElementAt(idx--);
756 else
757 te_is_identity = false;
758 }
759
760
761
762
763 try
764 {
765 String hdr;
766 if ((hdr = (String) Headers.get("Content-Type")) != null)
767 {
768 Vector phdr = Util.parseHeader(hdr);
769 ct_mpbr = phdr.contains(new HttpHeaderElement("multipart/byteranges")) ||
770 phdr.contains(new HttpHeaderElement("multipart/x-byteranges"));
771 }
772 }
773 catch (ParseException pe)
774 { }
775
776
777
778
779 if (StatusCode < 200 || StatusCode == 204 || StatusCode == 205 ||
780 StatusCode == 304)
781 {
782 cd_type = CD_0;
783 }
784 else if (te_chunked)
785 {
786 cd_type = CD_CHUNKED;
787
788 te_hdr.removeElementAt(te_hdr.size()-1);
789 if (te_hdr.size() > 0)
790 setHeader("Transfer-Encoding", Util.assembleHeader(te_hdr));
791 else
792 deleteHeader("Transfer-Encoding");
793 }
794 else if (cont_len != -1 && te_is_identity)
795 cd_type = CD_CONTLEN;
796 else if (ct_mpbr && te_is_identity)
797 cd_type = CD_MP_BR;
798 else if (!method.equals("HEAD"))
799 {
800 cd_type = CD_CLOSE;
801 if (stream_handler != null)
802 stream_handler.markForClose(this);
803
804 if (Version.equals("HTTP/0.9"))
805 {
806 inp_stream =
807 new SequenceInputStream(new ByteArrayInputStream(Data),
808 inp_stream);
809 Data = null;
810 }
811 }
812
813 if (cd_type == CD_CONTLEN)
814 ContentLength = cont_len;
815 else
816 deleteHeader("Content-Length");
817
818
819
820
821 if (method.equals("HEAD"))
822 cd_type = CD_0;
823
824 if (cd_type == CD_0)
825 {
826 ContentLength = 0;
827 Data = new byte[0];
828 inp_stream.close();
829 }
830
831 Log.write(Log.RESP, "Resp: Response entity delimiter: " +
832 (cd_type == CD_0 ? "No Entity" :
833 cd_type == CD_CLOSE ? "Close" :
834 cd_type == CD_CONTLEN ? "Content-Length" :
835 cd_type == CD_CHUNKED ? "Chunked" :
836 cd_type == CD_MP_BR ? "Multipart" :
837 "???" ) + " (" + inp_stream.hashCode() + ")");
838
839
840
841
842 if (connection.ServerProtocolVersion >= HTTP_1_1)
843 deleteHeader("Proxy-Connection");
844 else
845 {
846 if (connection.getProxyHost() != null)
847 deleteHeader("Connection");
848 else
849 deleteHeader("Proxy-Connection");
850
851 Vector pco;
852 try
853 { pco = Util.parseHeader((String) Headers.get("Connection")); }
854 catch (ParseException pe)
855 { pco = null; }
856
857 if (pco != null)
858 {
859 for (int idx=0; idx<pco.size(); idx++)
860 {
861 String name =
862 ((HttpHeaderElement) pco.elementAt(idx)).getName();
863 if (!name.equalsIgnoreCase("keep-alive"))
864 {
865 pco.removeElementAt(idx);
866 deleteHeader(name);
867 idx--;
868 }
869 }
870
871 if (pco.size() > 0)
872 setHeader("Connection", Util.assembleHeader(pco));
873 else
874 deleteHeader("Connection");
875 }
876
877 try
878 { pco = Util.parseHeader((String) Headers.get("Proxy-Connection")); }
879 catch (ParseException pe)
880 { pco = null; }
881
882 if (pco != null)
883 {
884 for (int idx=0; idx<pco.size(); idx++)
885 {
886 String name =
887 ((HttpHeaderElement) pco.elementAt(idx)).getName();
888 if (!name.equalsIgnoreCase("keep-alive"))
889 {
890 pco.removeElementAt(idx);
891 deleteHeader(name);
892 idx--;
893 }
894 }
895
896 if (pco.size() > 0)
897 setHeader("Proxy-Connection", Util.assembleHeader(pco));
898 else
899 deleteHeader("Proxy-Connection");
900 }
901 }
902
903
904
905 got_headers = true;
906
907
908 if (isFirstResponse)
909 {
910 if (!connection.handleFirstRequest(req, this))
911 {
912
913 Response resp;
914 try
915 { resp = connection.sendRequest(req, timeout); }
916 catch (ModuleException me)
917 { throw new IOException(me.toString()); }
918 resp.getVersion();
919
920 this.StatusCode = resp.StatusCode;
921 this.ReasonLine = resp.ReasonLine;
922 this.Version = resp.Version;
923 this.EffectiveURI = resp.EffectiveURI;
924 this.ContentLength = resp.ContentLength;
925 this.Headers = resp.Headers;
926 this.inp_stream = resp.inp_stream;
927 this.Data = resp.Data;
928
929 req = null;
930 }
931 }
932 }
933
934
935
936
937
938 private byte[] buf = new byte[7];
939 private int buf_pos = 0;
940 private StringBuffer hdrs = new StringBuffer(400);
941 private boolean reading_lines = false;
942 private boolean bol = true;
943 private boolean got_cr = false;
944
945 private long ttfb = 0;
946
947
948
949
950
951
952
953
954
955
956
957
958 private String readResponseHeaders(InputStream inp) throws IOException
959 {
960 if (buf_pos == 0)
961 Log.write(Log.RESP, "Resp: Reading Response headers " +
962 inp_stream.hashCode());
963 else
964 Log.write(Log.RESP, "Resp: Resuming reading Response headers " +
965 inp_stream.hashCode());
966
967
968
969 if (!reading_lines)
970 {
971 try
972 {
973
974 if (buf_pos == 0)
975 {
976 int c;
977 boolean gotFirstByte = false;
978 do
979 {
980 if ((c = inp.read()) == -1)
981 throw new EOFException("Encountered premature EOF "
982 + "while reading Version");
983
984 if (!gotFirstByte) {
985 gotFirstByte = true;
986 ttfb =
987 connection.getTimeAuthority().getTimeInMilliseconds();
988 }
989
990 } while (Character.isWhitespace((char) c)) ;
991 buf[0] = (byte) c;
992 buf_pos = 1;
993 }
994
995
996 while (buf_pos < buf.length)
997 {
998 int got = inp.read(buf, buf_pos, buf.length-buf_pos);
999 if (got == -1)
1000 throw new EOFException("Encountered premature EOF " +
1001 "while reading Version");
1002 buf_pos += got;
1003 }
1004 }
1005 catch (EOFException eof)
1006 {
1007 Log.write(Log.RESP, "Resp: (" + inp_stream.hashCode() + ")",
1008 eof);
1009
1010 throw eof;
1011 }
1012 for (int idx=0; idx<buf.length; idx++)
1013 hdrs.append((char) buf[idx]);
1014
1015 reading_lines = true;
1016 }
1017
1018 if (hdrs.toString().startsWith("HTTP/") ||
1019 hdrs.toString().startsWith("HTTP "))
1020 readLines(inp);
1021
1022
1023 buf_pos = 0;
1024 reading_lines = false;
1025 bol = true;
1026 got_cr = false;
1027
1028 String tmp = hdrs.toString();
1029 hdrs.setLength(0);
1030 return tmp;
1031 }
1032
1033 public long getTtfb(){
1034 return ttfb;
1035 }
1036
1037 boolean trailers_read = false;
1038
1039
1040
1041
1042
1043
1044
1045
1046 void readTrailers(InputStream inp) throws IOException
1047 {
1048 try
1049 {
1050 readLines(inp);
1051 trailers_read = true;
1052 }
1053 catch (IOException ioe)
1054 {
1055 if (!(ioe instanceof InterruptedIOException))
1056 exception = ioe;
1057 throw ioe;
1058 }
1059 }
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073 private void readLines(InputStream inp) throws IOException
1074 {
1075
1076
1077
1078
1079
1080 loop: while (true)
1081 {
1082 int b = inp.read();
1083 switch (b)
1084 {
1085 case -1:
1086 throw new EOFException("Encountered premature EOF while reading headers:\n" + hdrs);
1087 case '\r':
1088 got_cr = true;
1089 break;
1090 case '\n':
1091 if (bol) break loop;
1092 hdrs.append('\n');
1093 bol = true;
1094 got_cr = false;
1095 break;
1096 case ' ':
1097 case '\t':
1098 if (bol)
1099 {
1100
1101 hdrs.setCharAt(hdrs.length()-1, ' ');
1102 bol = false;
1103 break;
1104 }
1105 default:
1106 if (got_cr)
1107 {
1108 hdrs.append('\r');
1109 got_cr = false;
1110 }
1111 hdrs.append((char) (b & 0xFF));
1112 bol = false;
1113 break;
1114 }
1115 }
1116 }
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126 private void parseResponseHeaders(String headers) throws ProtocolException
1127 {
1128 String sts_line = null;
1129 StringTokenizer lines = new StringTokenizer(headers, "\r\n"),
1130 elem;
1131
1132 if (Log.isEnabled(Log.RESP))
1133 Log.write(Log.RESP, "Resp: Parsing Response headers from Request "+
1134 "\"" + method + " " + resource + "\": (" +
1135 inp_stream.hashCode() + ")\n\n" + headers);
1136
1137
1138
1139
1140 if (!headers.regionMatches(true, 0, "HTTP/", 0, 5) &&
1141 !headers.regionMatches(true, 0, "HTTP ", 0, 5))
1142 {
1143 Version = "HTTP/0.9";
1144 StatusCode = 200;
1145 ReasonLine = "OK";
1146
1147 try
1148 { Data = headers.getBytes("8859_1"); }
1149 catch (UnsupportedEncodingException uee)
1150 { throw new Error(uee.toString()); }
1151
1152 return;
1153 }
1154
1155
1156
1157
1158 try
1159 {
1160 sts_line = lines.nextToken();
1161 elem = new StringTokenizer(sts_line, " \t");
1162
1163 Version = elem.nextToken();
1164 StatusCode = Integer.valueOf(elem.nextToken()).intValue();
1165
1166 if (Version.equalsIgnoreCase("HTTP"))
1167 Version = "HTTP/1.0";
1168 }
1169 catch (NoSuchElementException e)
1170 {
1171 throw new ProtocolException("Invalid HTTP status line received: " +
1172 sts_line);
1173 }
1174 try
1175 { ReasonLine = elem.nextToken("").trim(); }
1176 catch (NoSuchElementException e)
1177 { ReasonLine = ""; }
1178
1179
1180
1181
1182
1183
1184
1185 if (StatusCode >= 300 && sent_entity)
1186 {
1187 if (stream_handler != null)
1188 stream_handler.markForClose(this);
1189 }
1190
1191
1192
1193
1194 parseHeaderFields(lines, Headers);
1195
1196
1197
1198
1199
1200 if (Headers.get("Trailer") != null && resp_inp_stream != null)
1201 resp_inp_stream.dontTruncate();
1202
1203
1204
1205 int vers;
1206 if (Version.equalsIgnoreCase("HTTP/0.9") ||
1207 Version.equalsIgnoreCase("HTTP/1.0"))
1208 vers = 0;
1209 else
1210 vers = 1;
1211
1212 try
1213 {
1214 String con = (String) Headers.get("Connection"),
1215 pcon = (String) Headers.get("Proxy-Connection");
1216
1217
1218 if ((vers == 1 && con != null && Util.hasToken(con, "close"))
1219 ||
1220 (vers == 0 &&
1221 !((!used_proxy && con != null &&
1222 Util.hasToken(con, "keep-alive")) ||
1223 (used_proxy && pcon != null &&
1224 Util.hasToken(pcon, "keep-alive")))
1225 )
1226 )
1227 if (stream_handler != null)
1228 stream_handler.markForClose(this);
1229 }
1230 catch (ParseException pe) { }
1231 }
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242 private synchronized void getTrailers() throws IOException
1243 {
1244 if (got_trailers) return;
1245 if (exception != null)
1246 {
1247 exception.fillInStackTrace();
1248 throw exception;
1249 }
1250
1251 Log.write(Log.RESP, "Resp: Reading Response trailers " +
1252 inp_stream.hashCode());
1253
1254 try
1255 {
1256 if (!trailers_read)
1257 {
1258 if (resp_inp_stream != null)
1259 resp_inp_stream.readAll(timeout);
1260 }
1261
1262 if (trailers_read)
1263 {
1264 Log.write(Log.RESP, "Resp: Parsing Response trailers from "+
1265 "Request \"" + method + " " + resource +
1266 "\": (" + inp_stream.hashCode() +
1267 ")\n\n" + hdrs);
1268
1269 parseHeaderFields(new StringTokenizer(hdrs.toString(), "\r\n"),
1270 Trailers);
1271 }
1272 }
1273 finally
1274 {
1275 got_trailers = true;
1276 }
1277 }
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289 private void parseHeaderFields(StringTokenizer lines, CIHashtable list)
1290 throws ProtocolException
1291 {
1292 while (lines.hasMoreTokens())
1293 {
1294 String hdr = lines.nextToken();
1295 int sep = hdr.indexOf(':');
1296
1297
1298
1299
1300
1301 if (sep == -1)
1302 sep = hdr.indexOf(' ');
1303 if (sep == -1)
1304 {
1305 throw new ProtocolException("Invalid HTTP header received: " +
1306 hdr);
1307 }
1308
1309 String hdr_name = hdr.substring(0, sep).trim();
1310 String hdr_value = hdr.substring(sep+1).trim();
1311
1312
1313 if (!singleValueHeaders.containsKey(hdr_name.toLowerCase()))
1314 {
1315 String old_value = (String) list.get(hdr_name);
1316 if (old_value == null)
1317 list.put(hdr_name, hdr_value);
1318 else
1319 list.put(hdr_name, old_value + ", " + hdr_value);
1320 }
1321 else
1322
1323 list.put(hdr_name, hdr_value);
1324 }
1325 }
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335 private void readResponseData(InputStream inp) throws IOException
1336 {
1337 if (ContentLength == 0)
1338 return;
1339
1340 if (Data == null)
1341 Data = new byte[0];
1342
1343
1344
1345
1346 int off = Data.length;
1347
1348 try
1349 {
1350
1351 if (getHeader("Content-Length") != null)
1352 {
1353 int rcvd = 0;
1354 Data = new byte[ContentLength];
1355
1356 do
1357 {
1358 off += rcvd;
1359 rcvd = inp.read(Data, off, ContentLength-off);
1360 } while (rcvd != -1 && off+rcvd < ContentLength);
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 }
1375 else
1376 {
1377 int inc = 1000,
1378 rcvd = 0;
1379
1380 do
1381 {
1382 off += rcvd;
1383 Data = Util.resizeArray(Data, off+inc);
1384 } while ((rcvd = inp.read(Data, off, inc)) != -1);
1385
1386 Data = Util.resizeArray(Data, off);
1387 }
1388 }
1389 catch (IOException ioe)
1390 {
1391 Data = Util.resizeArray(Data, off);
1392 throw ioe;
1393 }
1394 finally
1395 {
1396 try
1397 { inp.close(); }
1398 catch (IOException ioe)
1399 { }
1400 }
1401 }
1402
1403
1404 Request req = null;
1405 boolean isFirstResponse = false;
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416 void markAsFirstResponse(Request req)
1417 {
1418 this.req = req;
1419 isFirstResponse = true;
1420 }
1421
1422
1423
1424
1425
1426 public Object clone()
1427 {
1428 Response cl;
1429 try
1430 { cl = (Response) super.clone(); }
1431 catch (CloneNotSupportedException cnse)
1432 { throw new InternalError(cnse.toString());
1433
1434 cl.Headers = (CIHashtable) Headers.clone();
1435 cl.Trailers = (CIHashtable) Trailers.clone();
1436
1437 return cl;
1438 }
1439 }