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 LOG.debug("URI = {}",uri.toASCIIString());
597
598 String scheme = uri.getScheme();
599 int port = uri.getPort();
600 if (port <= 0)
601 port = "https".equalsIgnoreCase(scheme)?443:80;
602
603 setScheme(scheme);
604 setAddress(new Address(uri.getHost(),port));
605
606 HttpURI httpUri = new HttpURI(uri);
607 String completePath = httpUri.getCompletePath();
608 setRequestURI(completePath == null?"/":completePath);
609 }
610
611
612
613
614
615
616
617
618
619 public void addRequestHeader(String name, String value)
620 {
621 getRequestFields().add(name,value);
622 }
623
624
625
626
627
628
629
630
631
632 public void addRequestHeader(Buffer name, Buffer value)
633 {
634 getRequestFields().add(name,value);
635 }
636
637
638
639
640
641
642
643
644
645 public void setRequestHeader(String name, String value)
646 {
647 getRequestFields().put(name,value);
648 }
649
650
651
652
653
654
655
656
657
658 public void setRequestHeader(Buffer name, Buffer value)
659 {
660 getRequestFields().put(name,value);
661 }
662
663
664
665
666
667 public void setRequestContentType(String value)
668 {
669 getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
670 }
671
672
673
674
675 public HttpFields getRequestFields()
676 {
677 return _requestFields;
678 }
679
680
681
682
683
684 public void setRequestContent(Buffer requestContent)
685 {
686 _requestContent = requestContent;
687 }
688
689
690
691
692
693 public void setRequestContentSource(InputStream stream)
694 {
695 _requestContentSource = stream;
696 if (_requestContentSource != null && _requestContentSource.markSupported())
697 _requestContentSource.mark(Integer.MAX_VALUE);
698 }
699
700
701
702
703 public InputStream getRequestContentSource()
704 {
705 return _requestContentSource;
706 }
707
708 public Buffer getRequestContentChunk() throws IOException
709 {
710 synchronized (this)
711 {
712 if (_requestContentChunk == null)
713 _requestContentChunk = new ByteArrayBuffer(4096);
714 else
715 {
716 if (_requestContentChunk.hasContent())
717 throw new IllegalStateException();
718 _requestContentChunk.clear();
719 }
720
721 int read = _requestContentChunk.capacity();
722 int length = _requestContentSource.read(_requestContentChunk.array(),0,read);
723 if (length >= 0)
724 {
725 _requestContentChunk.setPutIndex(length);
726 return _requestContentChunk;
727 }
728 return null;
729 }
730 }
731
732
733
734
735 public Buffer getRequestContent()
736 {
737 return _requestContent;
738 }
739
740
741
742
743 public boolean getRetryStatus()
744 {
745 return _retryStatus;
746 }
747
748
749
750
751
752 public void setRetryStatus(boolean retryStatus)
753 {
754 _retryStatus = retryStatus;
755 }
756
757
758
759
760
761
762
763 public void cancel()
764 {
765 setStatus(STATUS_CANCELLING);
766 abort();
767 }
768
769 private void done()
770 {
771 synchronized (this)
772 {
773 disassociate();
774 _onDone = true;
775 notifyAll();
776 }
777 }
778
779 private void abort()
780 {
781 HttpConnection httpConnection = _connection;
782 if (httpConnection != null)
783 {
784 try
785 {
786
787
788 httpConnection.close();
789 }
790 catch (IOException x)
791 {
792 LOG.debug(x);
793 }
794 finally
795 {
796 disassociate();
797 }
798 }
799 }
800
801 void associate(HttpConnection connection)
802 {
803 if (connection.getEndPoint().getLocalHost() != null)
804 _localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
805
806 _connection = connection;
807 if (getStatus() == STATUS_CANCELLING)
808 abort();
809 }
810
811 boolean isAssociated()
812 {
813 return this._connection != null;
814 }
815
816 HttpConnection disassociate()
817 {
818 HttpConnection result = _connection;
819 this._connection = null;
820 if (getStatus() == STATUS_CANCELLING)
821 setStatus(STATUS_CANCELLED);
822 return result;
823 }
824
825 public static String toState(int s)
826 {
827 String state;
828 switch (s)
829 {
830 case STATUS_START:
831 state = "START";
832 break;
833 case STATUS_WAITING_FOR_CONNECTION:
834 state = "CONNECTING";
835 break;
836 case STATUS_WAITING_FOR_COMMIT:
837 state = "CONNECTED";
838 break;
839 case STATUS_SENDING_REQUEST:
840 state = "SENDING";
841 break;
842 case STATUS_WAITING_FOR_RESPONSE:
843 state = "WAITING";
844 break;
845 case STATUS_PARSING_HEADERS:
846 state = "HEADERS";
847 break;
848 case STATUS_PARSING_CONTENT:
849 state = "CONTENT";
850 break;
851 case STATUS_COMPLETED:
852 state = "COMPLETED";
853 break;
854 case STATUS_EXPIRED:
855 state = "EXPIRED";
856 break;
857 case STATUS_EXCEPTED:
858 state = "EXCEPTED";
859 break;
860 case STATUS_CANCELLING:
861 state = "CANCELLING";
862 break;
863 case STATUS_CANCELLED:
864 state = "CANCELLED";
865 break;
866 default:
867 state = "UNKNOWN";
868 }
869 return state;
870 }
871
872 @Override
873 public String toString()
874 {
875 String state=toState(getStatus());
876 long now=System.currentTimeMillis();
877 long forMs = now -_lastStateChange;
878 String s= _lastState>=0
879 ?String.format("%s@%x=%s//%s%s#%s(%dms)->%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,toState(_lastState),_lastStatePeriod,state,forMs)
880 :String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
881 if (getStatus()>=STATUS_SENDING_REQUEST && _sent>0)
882 s+="sent="+(now-_sent)+"ms";
883 return s;
884 }
885
886
887
888 protected Connection onSwitchProtocol(EndPoint endp) throws IOException
889 {
890 return null;
891 }
892
893
894
895
896
897
898
899 protected void onRequestCommitted() throws IOException
900 {
901 }
902
903
904
905
906
907
908
909 protected void onRequestComplete() throws IOException
910 {
911 }
912
913
914
915
916
917
918
919
920
921
922
923
924
925 protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
926 {
927 }
928
929
930
931
932
933
934
935
936
937
938
939 protected void onResponseHeader(Buffer name, Buffer value) throws IOException
940 {
941 }
942
943
944
945
946
947
948
949 protected void onResponseHeaderComplete() throws IOException
950 {
951 }
952
953
954
955
956
957
958
959
960
961 protected void onResponseContent(Buffer content) throws IOException
962 {
963 }
964
965
966
967
968
969
970
971 protected void onResponseComplete() throws IOException
972 {
973 }
974
975
976
977
978
979
980
981
982 protected void onConnectionFailed(Throwable x)
983 {
984 LOG.warn("CONNECTION FAILED " + this,x);
985 }
986
987
988
989
990
991
992
993 protected void onException(Throwable x)
994 {
995 LOG.warn("EXCEPTION " + this,x);
996 }
997
998
999
1000
1001 protected void onExpire()
1002 {
1003 LOG.warn("EXPIRED " + this);
1004 }
1005
1006
1007
1008
1009
1010
1011
1012 protected void onRetry() throws IOException
1013 {
1014 if (_requestContentSource != null)
1015 {
1016 if (_requestContentSource.markSupported())
1017 {
1018 _requestContent = null;
1019 _requestContentSource.reset();
1020 }
1021 else
1022 {
1023 throw new IOException("Unsupported retry attempt");
1024 }
1025 }
1026 }
1027
1028
1029
1030
1031
1032 public boolean configureListeners()
1033 {
1034 return _configureListeners;
1035 }
1036
1037
1038
1039
1040
1041 public void setConfigureListeners(boolean autoConfigure)
1042 {
1043 this._configureListeners = autoConfigure;
1044 }
1045
1046 protected void scheduleTimeout(final HttpDestination destination)
1047 {
1048 assert _timeoutTask == null;
1049
1050 _timeoutTask = new Timeout.Task()
1051 {
1052 @Override
1053 public void expired()
1054 {
1055 HttpExchange.this.expire(destination);
1056 }
1057 };
1058
1059 HttpClient httpClient = destination.getHttpClient();
1060 long timeout = getTimeout();
1061 if (timeout > 0)
1062 httpClient.schedule(_timeoutTask,timeout);
1063 else
1064 httpClient.schedule(_timeoutTask);
1065 }
1066
1067 protected void cancelTimeout(HttpClient httpClient)
1068 {
1069 Timeout.Task task = _timeoutTask;
1070 if (task != null)
1071 httpClient.cancel(task);
1072 _timeoutTask = null;
1073 }
1074
1075 private class Listener implements HttpEventListener
1076 {
1077 public void onConnectionFailed(Throwable ex)
1078 {
1079 try
1080 {
1081 HttpExchange.this.onConnectionFailed(ex);
1082 }
1083 finally
1084 {
1085 done();
1086 }
1087 }
1088
1089 public void onException(Throwable ex)
1090 {
1091 try
1092 {
1093 HttpExchange.this.onException(ex);
1094 }
1095 finally
1096 {
1097 done();
1098 }
1099 }
1100
1101 public void onExpire()
1102 {
1103 try
1104 {
1105 HttpExchange.this.onExpire();
1106 }
1107 finally
1108 {
1109 done();
1110 }
1111 }
1112
1113 public void onRequestCommitted() throws IOException
1114 {
1115 HttpExchange.this.onRequestCommitted();
1116 }
1117
1118 public void onRequestComplete() throws IOException
1119 {
1120 try
1121 {
1122 HttpExchange.this.onRequestComplete();
1123 }
1124 finally
1125 {
1126 synchronized (HttpExchange.this)
1127 {
1128 _onRequestCompleteDone = true;
1129
1130
1131 _onDone |= _onResponseCompleteDone;
1132 if (_onDone)
1133 disassociate();
1134 HttpExchange.this.notifyAll();
1135 }
1136 }
1137 }
1138
1139 public void onResponseComplete() throws IOException
1140 {
1141 try
1142 {
1143 HttpExchange.this.onResponseComplete();
1144 }
1145 finally
1146 {
1147 synchronized (HttpExchange.this)
1148 {
1149 _onResponseCompleteDone = true;
1150
1151
1152 _onDone |= _onRequestCompleteDone;
1153 if (_onDone)
1154 disassociate();
1155 HttpExchange.this.notifyAll();
1156 }
1157 }
1158 }
1159
1160 public void onResponseContent(Buffer content) throws IOException
1161 {
1162 HttpExchange.this.onResponseContent(content);
1163 }
1164
1165 public void onResponseHeader(Buffer name, Buffer value) throws IOException
1166 {
1167 HttpExchange.this.onResponseHeader(name,value);
1168 }
1169
1170 public void onResponseHeaderComplete() throws IOException
1171 {
1172 HttpExchange.this.onResponseHeaderComplete();
1173 }
1174
1175 public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
1176 {
1177 HttpExchange.this.onResponseStatus(version,status,reason);
1178 }
1179
1180 public void onRetry()
1181 {
1182 HttpExchange.this.setRetryStatus(true);
1183 try
1184 {
1185 HttpExchange.this.onRetry();
1186 }
1187 catch (IOException e)
1188 {
1189 LOG.debug(e);
1190 }
1191 }
1192 }
1193
1194
1195
1196
1197 @Deprecated
1198 public static class CachedExchange extends org.eclipse.jetty.client.CachedExchange
1199 {
1200 public CachedExchange(boolean cacheFields)
1201 {
1202 super(cacheFields);
1203 }
1204 }
1205
1206
1207
1208
1209 @Deprecated
1210 public static class ContentExchange extends org.eclipse.jetty.client.ContentExchange
1211 {
1212 }
1213 }