1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.client;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.net.URI;
19 import java.util.concurrent.atomic.AtomicInteger;
20
21 import org.eclipse.jetty.client.security.SecurityListener;
22 import org.eclipse.jetty.http.HttpFields;
23 import org.eclipse.jetty.http.HttpHeaders;
24 import org.eclipse.jetty.http.HttpMethods;
25 import org.eclipse.jetty.http.HttpSchemes;
26 import org.eclipse.jetty.http.HttpURI;
27 import org.eclipse.jetty.http.HttpVersions;
28 import org.eclipse.jetty.io.Buffer;
29 import org.eclipse.jetty.io.BufferCache.CachedBuffer;
30 import org.eclipse.jetty.io.ByteArrayBuffer;
31 import org.eclipse.jetty.io.Connection;
32 import org.eclipse.jetty.io.EndPoint;
33 import org.eclipse.jetty.util.log.Log;
34 import org.eclipse.jetty.util.log.Logger;
35 import org.eclipse.jetty.util.thread.Timeout;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class HttpExchange
74 {
75 private static final Logger LOG = Log.getLogger(HttpExchange.class);
76
77 public static final int STATUS_START = 0;
78 public static final int STATUS_WAITING_FOR_CONNECTION = 1;
79 public static final int STATUS_WAITING_FOR_COMMIT = 2;
80 public static final int STATUS_SENDING_REQUEST = 3;
81 public static final int STATUS_WAITING_FOR_RESPONSE = 4;
82 public static final int STATUS_PARSING_HEADERS = 5;
83 public static final int STATUS_PARSING_CONTENT = 6;
84 public static final int STATUS_COMPLETED = 7;
85 public static final int STATUS_EXPIRED = 8;
86 public static final int STATUS_EXCEPTED = 9;
87 public static final int STATUS_CANCELLING = 10;
88 public static final int STATUS_CANCELLED = 11;
89
90
91 private String _method = HttpMethods.GET;
92 private Buffer _scheme = HttpSchemes.HTTP_BUFFER;
93 private String _uri;
94 private int _version = HttpVersions.HTTP_1_1_ORDINAL;
95 private Address _address;
96 private final HttpFields _requestFields = new HttpFields();
97 private Buffer _requestContent;
98 private InputStream _requestContentSource;
99
100 private AtomicInteger _status = new AtomicInteger(STATUS_START);
101 private Buffer _requestContentChunk;
102 private boolean _retryStatus = false;
103
104 private boolean _configureListeners = true;
105 private HttpEventListener _listener = new Listener();
106 private volatile HttpConnection _connection;
107
108 private Address _localAddress = null;
109
110
111 private long _timeout = -1;
112 private volatile Timeout.Task _timeoutTask;
113 private long _lastStateChange=System.currentTimeMillis();
114 private long _sent=-1;
115 private int _lastState=-1;
116 private int _lastStatePeriod=-1;
117
118 boolean _onRequestCompleteDone;
119 boolean _onResponseCompleteDone;
120 boolean _onDone;
121
122 protected void expire(HttpDestination destination)
123 {
124 if (getStatus() < HttpExchange.STATUS_COMPLETED)
125 setStatus(HttpExchange.STATUS_EXPIRED);
126
127 destination.exchangeExpired(this);
128 HttpConnection connection = _connection;
129 if (connection != null)
130 connection.exchangeExpired(this);
131 }
132
133 public int getStatus()
134 {
135 return _status.get();
136 }
137
138
139
140
141
142
143
144
145 @Deprecated
146 public void waitForStatus(int status) throws InterruptedException
147 {
148 throw new UnsupportedOperationException();
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162 public int waitForDone() throws InterruptedException
163 {
164 synchronized (this)
165 {
166 while (!isDone())
167 this.wait();
168 return _status.get();
169 }
170 }
171
172 public void reset()
173 {
174
175
176 synchronized (this)
177 {
178 _timeoutTask = null;
179 _onRequestCompleteDone = false;
180 _onResponseCompleteDone = false;
181 _onDone = false;
182 setStatus(STATUS_START);
183 }
184 }
185
186 void setStatus(int newStatus)
187 {
188 try
189 {
190 int oldStatus = _status.get();
191 boolean set = false;
192 if (oldStatus != newStatus)
193 {
194 long now = System.currentTimeMillis();
195 _lastStatePeriod=(int)(now-_lastStateChange);
196 _lastState=oldStatus;
197 _lastStateChange=now;
198 if (newStatus==STATUS_SENDING_REQUEST)
199 _sent=_lastStateChange;
200 }
201
202
203 switch (oldStatus)
204 {
205 case STATUS_START:
206 switch (newStatus)
207 {
208 case STATUS_START:
209 case STATUS_WAITING_FOR_CONNECTION:
210 case STATUS_WAITING_FOR_COMMIT:
211 case STATUS_CANCELLING:
212 case STATUS_EXCEPTED:
213 set = _status.compareAndSet(oldStatus,newStatus);
214 break;
215 case STATUS_EXPIRED:
216 set = setStatusExpired(newStatus,oldStatus);
217 break;
218 }
219 break;
220 case STATUS_WAITING_FOR_CONNECTION:
221 switch (newStatus)
222 {
223 case STATUS_WAITING_FOR_COMMIT:
224 case STATUS_CANCELLING:
225 case STATUS_EXCEPTED:
226 set = _status.compareAndSet(oldStatus,newStatus);
227 break;
228 case STATUS_EXPIRED:
229 set = setStatusExpired(newStatus,oldStatus);
230 break;
231 }
232 break;
233 case STATUS_WAITING_FOR_COMMIT:
234 switch (newStatus)
235 {
236 case STATUS_SENDING_REQUEST:
237 case STATUS_CANCELLING:
238 case STATUS_EXCEPTED:
239 set = _status.compareAndSet(oldStatus,newStatus);
240 break;
241 case STATUS_EXPIRED:
242 set = setStatusExpired(newStatus,oldStatus);
243 break;
244 }
245 break;
246 case STATUS_SENDING_REQUEST:
247 switch (newStatus)
248 {
249 case STATUS_WAITING_FOR_RESPONSE:
250 if (set = _status.compareAndSet(oldStatus,newStatus))
251 getEventListener().onRequestCommitted();
252 break;
253 case STATUS_CANCELLING:
254 case STATUS_EXCEPTED:
255 set = _status.compareAndSet(oldStatus,newStatus);
256 break;
257 case STATUS_EXPIRED:
258 set = setStatusExpired(newStatus,oldStatus);
259 break;
260 }
261 break;
262 case STATUS_WAITING_FOR_RESPONSE:
263 switch (newStatus)
264 {
265 case STATUS_PARSING_HEADERS:
266 case STATUS_CANCELLING:
267 case STATUS_EXCEPTED:
268 set = _status.compareAndSet(oldStatus,newStatus);
269 break;
270 case STATUS_EXPIRED:
271 set = setStatusExpired(newStatus,oldStatus);
272 break;
273 }
274 break;
275 case STATUS_PARSING_HEADERS:
276 switch (newStatus)
277 {
278 case STATUS_PARSING_CONTENT:
279 if (set = _status.compareAndSet(oldStatus,newStatus))
280 getEventListener().onResponseHeaderComplete();
281 break;
282 case STATUS_CANCELLING:
283 case STATUS_EXCEPTED:
284 set = _status.compareAndSet(oldStatus,newStatus);
285 break;
286 case STATUS_EXPIRED:
287 set = setStatusExpired(newStatus,oldStatus);
288 break;
289 }
290 break;
291 case STATUS_PARSING_CONTENT:
292 switch (newStatus)
293 {
294 case STATUS_COMPLETED:
295 if (set = _status.compareAndSet(oldStatus,newStatus))
296 getEventListener().onResponseComplete();
297 break;
298 case STATUS_CANCELLING:
299 case STATUS_EXCEPTED:
300 set = _status.compareAndSet(oldStatus,newStatus);
301 break;
302 case STATUS_EXPIRED:
303 set = setStatusExpired(newStatus,oldStatus);
304 break;
305 }
306 break;
307 case STATUS_COMPLETED:
308 switch (newStatus)
309 {
310 case STATUS_START:
311 case STATUS_EXCEPTED:
312 case STATUS_WAITING_FOR_RESPONSE:
313 set = _status.compareAndSet(oldStatus,newStatus);
314 break;
315 case STATUS_CANCELLING:
316 case STATUS_EXPIRED:
317
318 set = true;
319 break;
320 }
321 break;
322 case STATUS_CANCELLING:
323 switch (newStatus)
324 {
325 case STATUS_EXCEPTED:
326 case STATUS_CANCELLED:
327 if (set = _status.compareAndSet(oldStatus,newStatus))
328 done();
329 break;
330 default:
331
332 set = true;
333 break;
334 }
335 break;
336 case STATUS_EXCEPTED:
337 case STATUS_EXPIRED:
338 case STATUS_CANCELLED:
339 switch (newStatus)
340 {
341 case STATUS_START:
342 set = _status.compareAndSet(oldStatus,newStatus);
343 break;
344 default:
345 set = true;
346 break;
347 }
348 break;
349 default:
350
351 throw new AssertionError(oldStatus + " => " + newStatus);
352 }
353
354 if (!set)
355 throw new IllegalStateException(toState(oldStatus) + " => " + toState(newStatus));
356 }
357 catch (IOException x)
358 {
359 LOG.warn(x);
360 }
361 }
362
363 private boolean setStatusExpired(int newStatus, int oldStatus)
364 {
365 boolean set;
366 if (set = _status.compareAndSet(oldStatus,newStatus))
367 getEventListener().onExpire();
368 return set;
369 }
370
371 public boolean isDone()
372 {
373 synchronized (this)
374 {
375 return _onDone;
376 }
377 }
378
379
380
381
382 @Deprecated
383 public boolean isDone(int status)
384 {
385 return isDone();
386 }
387
388 public HttpEventListener getEventListener()
389 {
390 return _listener;
391 }
392
393 public void setEventListener(HttpEventListener listener)
394 {
395 _listener = listener;
396 }
397
398 public void setTimeout(long timeout)
399 {
400 _timeout = timeout;
401 }
402
403 public long getTimeout()
404 {
405 return _timeout;
406 }
407
408
409
410
411
412 public void setURL(String url)
413 {
414 setURI(URI.create(url));
415 }
416
417
418
419
420
421 public void setAddress(Address address)
422 {
423 _address = address;
424 }
425
426
427
428
429 public Address getAddress()
430 {
431 return _address;
432 }
433
434
435
436
437
438
439
440
441 public Address getLocalAddress()
442 {
443 return _localAddress;
444 }
445
446
447
448
449
450 public void setScheme(Buffer scheme)
451 {
452 _scheme = scheme;
453 }
454
455
456
457
458
459 public void setScheme(String scheme)
460 {
461 if (scheme != null)
462 {
463 if (HttpSchemes.HTTP.equalsIgnoreCase(scheme))
464 setScheme(HttpSchemes.HTTP_BUFFER);
465 else if (HttpSchemes.HTTPS.equalsIgnoreCase(scheme))
466 setScheme(HttpSchemes.HTTPS_BUFFER);
467 else
468 setScheme(new ByteArrayBuffer(scheme));
469 }
470 }
471
472
473
474
475 public Buffer getScheme()
476 {
477 return _scheme;
478 }
479
480
481
482
483
484 public void setVersion(int version)
485 {
486 _version = version;
487 }
488
489
490
491
492
493 public void setVersion(String version)
494 {
495 CachedBuffer v = HttpVersions.CACHE.get(version);
496 if (v == null)
497 _version = 10;
498 else
499 _version = v.getOrdinal();
500 }
501
502
503
504
505
506 public int getVersion()
507 {
508 return _version;
509 }
510
511
512
513
514
515 public void setMethod(String method)
516 {
517 _method = method;
518 }
519
520
521
522
523 public String getMethod()
524 {
525 return _method;
526 }
527
528
529
530
531
532
533 @Deprecated
534 public String getURI()
535 {
536 return getRequestURI();
537 }
538
539
540
541
542 public String getRequestURI()
543 {
544 return _uri;
545 }
546
547
548
549
550
551
552
553
554
555 @Deprecated
556 public void setURI(String uri)
557 {
558 setRequestURI(uri);
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578 public void setRequestURI(String uri)
579 {
580 _uri = uri;
581 }
582
583
584
585
586
587
588 public void setURI(URI uri)
589 {
590 if (!uri.isAbsolute())
591 throw new IllegalArgumentException("!Absolute URI: " + uri);
592
593 if (uri.isOpaque())
594 throw new IllegalArgumentException("Opaque URI: " + uri);
595
596 if (LOG.isDebugEnabled())
597 LOG.debug("URI = {}",uri.toASCIIString());
598
599 String scheme = uri.getScheme();
600 int port = uri.getPort();
601 if (port <= 0)
602 port = "https".equalsIgnoreCase(scheme)?443:80;
603
604 setScheme(scheme);
605 setAddress(new Address(uri.getHost(),port));
606
607 HttpURI httpUri = new HttpURI(uri);
608 String completePath = httpUri.getCompletePath();
609 setRequestURI(completePath == null?"/":completePath);
610 }
611
612
613
614
615
616
617
618
619
620 public void addRequestHeader(String name, String value)
621 {
622 getRequestFields().add(name,value);
623 }
624
625
626
627
628
629
630
631
632
633 public void addRequestHeader(Buffer name, Buffer value)
634 {
635 getRequestFields().add(name,value);
636 }
637
638
639
640
641
642
643
644
645
646 public void setRequestHeader(String name, String value)
647 {
648 getRequestFields().put(name,value);
649 }
650
651
652
653
654
655
656
657
658
659 public void setRequestHeader(Buffer name, Buffer value)
660 {
661 getRequestFields().put(name,value);
662 }
663
664
665
666
667
668 public void setRequestContentType(String value)
669 {
670 getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
671 }
672
673
674
675
676 public HttpFields getRequestFields()
677 {
678 return _requestFields;
679 }
680
681
682
683
684
685 public void setRequestContent(Buffer requestContent)
686 {
687 _requestContent = requestContent;
688 }
689
690
691
692
693
694 public void setRequestContentSource(InputStream stream)
695 {
696 _requestContentSource = stream;
697 if (_requestContentSource != null && _requestContentSource.markSupported())
698 _requestContentSource.mark(Integer.MAX_VALUE);
699 }
700
701
702
703
704 public InputStream getRequestContentSource()
705 {
706 return _requestContentSource;
707 }
708
709 public Buffer getRequestContentChunk() throws IOException
710 {
711 synchronized (this)
712 {
713 if (_requestContentChunk == null)
714 _requestContentChunk = new ByteArrayBuffer(4096);
715 else
716 {
717 if (_requestContentChunk.hasContent())
718 throw new IllegalStateException();
719 _requestContentChunk.clear();
720 }
721
722 int read = _requestContentChunk.capacity();
723 int length = _requestContentSource.read(_requestContentChunk.array(),0,read);
724 if (length >= 0)
725 {
726 _requestContentChunk.setPutIndex(length);
727 return _requestContentChunk;
728 }
729 return null;
730 }
731 }
732
733
734
735
736 public Buffer getRequestContent()
737 {
738 return _requestContent;
739 }
740
741
742
743
744 public boolean getRetryStatus()
745 {
746 return _retryStatus;
747 }
748
749
750
751
752
753 public void setRetryStatus(boolean retryStatus)
754 {
755 _retryStatus = retryStatus;
756 }
757
758
759
760
761
762
763
764 public void cancel()
765 {
766 setStatus(STATUS_CANCELLING);
767 abort();
768 }
769
770 private void done()
771 {
772 synchronized (this)
773 {
774 disassociate();
775 _onDone = true;
776 notifyAll();
777 }
778 }
779
780 private void abort()
781 {
782 HttpConnection httpConnection = _connection;
783 if (httpConnection != null)
784 {
785 try
786 {
787
788
789 httpConnection.close();
790 }
791 catch (IOException x)
792 {
793 LOG.debug(x);
794 }
795 finally
796 {
797 disassociate();
798 }
799 }
800 }
801
802 void associate(HttpConnection connection)
803 {
804 if (connection.getEndPoint().getLocalHost() != null)
805 _localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
806
807 _connection = connection;
808 if (getStatus() == STATUS_CANCELLING)
809 abort();
810 }
811
812 boolean isAssociated()
813 {
814 return this._connection != null;
815 }
816
817 HttpConnection disassociate()
818 {
819 HttpConnection result = _connection;
820 this._connection = null;
821 if (getStatus() == STATUS_CANCELLING)
822 setStatus(STATUS_CANCELLED);
823 return result;
824 }
825
826 public static String toState(int s)
827 {
828 String state;
829 switch (s)
830 {
831 case STATUS_START:
832 state = "START";
833 break;
834 case STATUS_WAITING_FOR_CONNECTION:
835 state = "CONNECTING";
836 break;
837 case STATUS_WAITING_FOR_COMMIT:
838 state = "CONNECTED";
839 break;
840 case STATUS_SENDING_REQUEST:
841 state = "SENDING";
842 break;
843 case STATUS_WAITING_FOR_RESPONSE:
844 state = "WAITING";
845 break;
846 case STATUS_PARSING_HEADERS:
847 state = "HEADERS";
848 break;
849 case STATUS_PARSING_CONTENT:
850 state = "CONTENT";
851 break;
852 case STATUS_COMPLETED:
853 state = "COMPLETED";
854 break;
855 case STATUS_EXPIRED:
856 state = "EXPIRED";
857 break;
858 case STATUS_EXCEPTED:
859 state = "EXCEPTED";
860 break;
861 case STATUS_CANCELLING:
862 state = "CANCELLING";
863 break;
864 case STATUS_CANCELLED:
865 state = "CANCELLED";
866 break;
867 default:
868 state = "UNKNOWN";
869 }
870 return state;
871 }
872
873 @Override
874 public String toString()
875 {
876 String state=toState(getStatus());
877 long now=System.currentTimeMillis();
878 long forMs = now -_lastStateChange;
879 String s= _lastState>=0
880 ?String.format("%s@%x=%s//%s%s#%s(%dms)->%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,toState(_lastState),_lastStatePeriod,state,forMs)
881 :String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
882 if (getStatus()>=STATUS_SENDING_REQUEST && _sent>0)
883 s+="sent="+(now-_sent)+"ms";
884 return s;
885 }
886
887
888
889 protected Connection onSwitchProtocol(EndPoint endp) throws IOException
890 {
891 return null;
892 }
893
894
895
896
897
898
899
900 protected void onRequestCommitted() throws IOException
901 {
902 }
903
904
905
906
907
908
909
910 protected void onRequestComplete() throws IOException
911 {
912 }
913
914
915
916
917
918
919
920
921
922
923
924
925
926 protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
927 {
928 }
929
930
931
932
933
934
935
936
937
938
939
940 protected void onResponseHeader(Buffer name, Buffer value) throws IOException
941 {
942 }
943
944
945
946
947
948
949
950 protected void onResponseHeaderComplete() throws IOException
951 {
952 }
953
954
955
956
957
958
959
960
961
962 protected void onResponseContent(Buffer content) throws IOException
963 {
964 }
965
966
967
968
969
970
971
972 protected void onResponseComplete() throws IOException
973 {
974 }
975
976
977
978
979
980
981
982
983 protected void onConnectionFailed(Throwable x)
984 {
985 LOG.warn("CONNECTION FAILED " + this,x);
986 }
987
988
989
990
991
992
993
994 protected void onException(Throwable x)
995 {
996 LOG.warn("EXCEPTION " + this,x);
997 }
998
999
1000
1001
1002 protected void onExpire()
1003 {
1004 LOG.warn("EXPIRED " + this);
1005 }
1006
1007
1008
1009
1010
1011
1012
1013 protected void onRetry() throws IOException
1014 {
1015 if (_requestContentSource != null)
1016 {
1017 if (_requestContentSource.markSupported())
1018 {
1019 _requestContent = null;
1020 _requestContentSource.reset();
1021 }
1022 else
1023 {
1024 throw new IOException("Unsupported retry attempt");
1025 }
1026 }
1027 }
1028
1029
1030
1031
1032
1033 public boolean configureListeners()
1034 {
1035 return _configureListeners;
1036 }
1037
1038
1039
1040
1041
1042 public void setConfigureListeners(boolean autoConfigure)
1043 {
1044 this._configureListeners = autoConfigure;
1045 }
1046
1047 protected void scheduleTimeout(final HttpDestination destination)
1048 {
1049 assert _timeoutTask == null;
1050
1051 _timeoutTask = new Timeout.Task()
1052 {
1053 @Override
1054 public void expired()
1055 {
1056 HttpExchange.this.expire(destination);
1057 }
1058 };
1059
1060 HttpClient httpClient = destination.getHttpClient();
1061 long timeout = getTimeout();
1062 if (timeout > 0)
1063 httpClient.schedule(_timeoutTask,timeout);
1064 else
1065 httpClient.schedule(_timeoutTask);
1066 }
1067
1068 protected void cancelTimeout(HttpClient httpClient)
1069 {
1070 Timeout.Task task = _timeoutTask;
1071 if (task != null)
1072 httpClient.cancel(task);
1073 _timeoutTask = null;
1074 }
1075
1076 private class Listener implements HttpEventListener
1077 {
1078 public void onConnectionFailed(Throwable ex)
1079 {
1080 try
1081 {
1082 HttpExchange.this.onConnectionFailed(ex);
1083 }
1084 finally
1085 {
1086 done();
1087 }
1088 }
1089
1090 public void onException(Throwable ex)
1091 {
1092 try
1093 {
1094 HttpExchange.this.onException(ex);
1095 }
1096 finally
1097 {
1098 done();
1099 }
1100 }
1101
1102 public void onExpire()
1103 {
1104 try
1105 {
1106 HttpExchange.this.onExpire();
1107 }
1108 finally
1109 {
1110 done();
1111 }
1112 }
1113
1114 public void onRequestCommitted() throws IOException
1115 {
1116 HttpExchange.this.onRequestCommitted();
1117 }
1118
1119 public void onRequestComplete() throws IOException
1120 {
1121 try
1122 {
1123 HttpExchange.this.onRequestComplete();
1124 }
1125 finally
1126 {
1127 synchronized (HttpExchange.this)
1128 {
1129 _onRequestCompleteDone = true;
1130
1131
1132 _onDone |= _onResponseCompleteDone;
1133 if (_onDone)
1134 disassociate();
1135 HttpExchange.this.notifyAll();
1136 }
1137 }
1138 }
1139
1140 public void onResponseComplete() throws IOException
1141 {
1142 try
1143 {
1144 HttpExchange.this.onResponseComplete();
1145 }
1146 finally
1147 {
1148 synchronized (HttpExchange.this)
1149 {
1150 _onResponseCompleteDone = true;
1151
1152
1153 _onDone |= _onRequestCompleteDone;
1154 if (_onDone)
1155 disassociate();
1156 HttpExchange.this.notifyAll();
1157 }
1158 }
1159 }
1160
1161 public void onResponseContent(Buffer content) throws IOException
1162 {
1163 HttpExchange.this.onResponseContent(content);
1164 }
1165
1166 public void onResponseHeader(Buffer name, Buffer value) throws IOException
1167 {
1168 HttpExchange.this.onResponseHeader(name,value);
1169 }
1170
1171 public void onResponseHeaderComplete() throws IOException
1172 {
1173 HttpExchange.this.onResponseHeaderComplete();
1174 }
1175
1176 public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
1177 {
1178 HttpExchange.this.onResponseStatus(version,status,reason);
1179 }
1180
1181 public void onRetry()
1182 {
1183 HttpExchange.this.setRetryStatus(true);
1184 try
1185 {
1186 HttpExchange.this.onRetry();
1187 }
1188 catch (IOException e)
1189 {
1190 LOG.debug(e);
1191 }
1192 }
1193 }
1194
1195
1196
1197
1198 @Deprecated
1199 public static class CachedExchange extends org.eclipse.jetty.client.CachedExchange
1200 {
1201 public CachedExchange(boolean cacheFields)
1202 {
1203 super(cacheFields);
1204 }
1205 }
1206
1207
1208
1209
1210 @Deprecated
1211 public static class ContentExchange extends org.eclipse.jetty.client.ContentExchange
1212 {
1213 }
1214 }