1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.client;
20
21 import java.net.CookieManager;
22 import java.net.CookiePolicy;
23 import java.net.CookieStore;
24 import java.net.InetSocketAddress;
25 import java.net.Socket;
26 import java.net.SocketAddress;
27 import java.net.URI;
28 import java.nio.channels.SelectionKey;
29 import java.nio.channels.SocketChannel;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Map;
38 import java.util.Objects;
39 import java.util.Set;
40 import java.util.concurrent.ConcurrentHashMap;
41 import java.util.concurrent.ConcurrentMap;
42 import java.util.concurrent.ExecutionException;
43 import java.util.concurrent.Executor;
44 import java.util.concurrent.TimeUnit;
45 import java.util.concurrent.TimeoutException;
46
47 import org.eclipse.jetty.client.api.AuthenticationStore;
48 import org.eclipse.jetty.client.api.Connection;
49 import org.eclipse.jetty.client.api.ContentResponse;
50 import org.eclipse.jetty.client.api.Destination;
51 import org.eclipse.jetty.client.api.Request;
52 import org.eclipse.jetty.client.api.Response;
53 import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
54 import org.eclipse.jetty.client.util.FormContentProvider;
55 import org.eclipse.jetty.http.HttpField;
56 import org.eclipse.jetty.http.HttpHeader;
57 import org.eclipse.jetty.http.HttpMethod;
58 import org.eclipse.jetty.http.HttpScheme;
59 import org.eclipse.jetty.io.ByteBufferPool;
60 import org.eclipse.jetty.io.MappedByteBufferPool;
61 import org.eclipse.jetty.util.Fields;
62 import org.eclipse.jetty.util.Jetty;
63 import org.eclipse.jetty.util.Promise;
64 import org.eclipse.jetty.util.SocketAddressResolver;
65 import org.eclipse.jetty.util.annotation.ManagedAttribute;
66 import org.eclipse.jetty.util.annotation.ManagedObject;
67 import org.eclipse.jetty.util.component.ContainerLifeCycle;
68 import org.eclipse.jetty.util.log.Log;
69 import org.eclipse.jetty.util.log.Logger;
70 import org.eclipse.jetty.util.ssl.SslContextFactory;
71 import org.eclipse.jetty.util.thread.QueuedThreadPool;
72 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
73 import org.eclipse.jetty.util.thread.Scheduler;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 @ManagedObject("The HTTP client")
112 public class HttpClient extends ContainerLifeCycle
113 {
114 private static final Logger LOG = Log.getLogger(HttpClient.class);
115
116 private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
117 private final ProtocolHandlers handlers = new ProtocolHandlers();
118 private final List<Request.Listener> requestListeners = new ArrayList<>();
119 private final AuthenticationStore authenticationStore = new HttpAuthenticationStore();
120 private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
121 private final ProxyConfiguration proxyConfig = new ProxyConfiguration();
122 private final HttpClientTransport transport;
123 private final SslContextFactory sslContextFactory;
124 private volatile CookieManager cookieManager;
125 private volatile CookieStore cookieStore;
126 private volatile Executor executor;
127 private volatile ByteBufferPool byteBufferPool;
128 private volatile Scheduler scheduler;
129 private volatile SocketAddressResolver resolver;
130 private volatile HttpField agentField = new HttpField(HttpHeader.USER_AGENT, "Jetty/" + Jetty.VERSION);
131 private volatile boolean followRedirects = true;
132 private volatile int maxConnectionsPerDestination = 64;
133 private volatile int maxRequestsQueuedPerDestination = 1024;
134 private volatile int requestBufferSize = 4096;
135 private volatile int responseBufferSize = 16384;
136 private volatile int maxRedirects = 8;
137 private volatile SocketAddress bindAddress;
138 private volatile long connectTimeout = 15000;
139 private volatile long addressResolutionTimeout = 15000;
140 private volatile long idleTimeout;
141 private volatile boolean tcpNoDelay = true;
142 private volatile boolean strictEventOrdering = false;
143 private volatile HttpField encodingField;
144 private volatile boolean removeIdleDestinations = false;
145 private volatile boolean connectBlocking = false;
146
147
148
149
150
151
152
153 public HttpClient()
154 {
155 this(null);
156 }
157
158
159
160
161
162
163
164
165 public HttpClient(SslContextFactory sslContextFactory)
166 {
167 this(new HttpClientTransportOverHTTP(), sslContextFactory);
168 }
169
170 public HttpClient(HttpClientTransport transport, SslContextFactory sslContextFactory)
171 {
172 this.transport = transport;
173 this.sslContextFactory = sslContextFactory;
174 }
175
176 public HttpClientTransport getTransport()
177 {
178 return transport;
179 }
180
181
182
183
184
185 public SslContextFactory getSslContextFactory()
186 {
187 return sslContextFactory;
188 }
189
190 @Override
191 protected void doStart() throws Exception
192 {
193 if (sslContextFactory != null)
194 addBean(sslContextFactory);
195
196 String name = HttpClient.class.getSimpleName() + "@" + hashCode();
197
198 if (executor == null)
199 {
200 QueuedThreadPool threadPool = new QueuedThreadPool();
201 threadPool.setName(name);
202 executor = threadPool;
203 }
204 addBean(executor);
205
206 if (byteBufferPool == null)
207 byteBufferPool = new MappedByteBufferPool();
208 addBean(byteBufferPool);
209
210 if (scheduler == null)
211 scheduler = new ScheduledExecutorScheduler(name + "-scheduler", false);
212 addBean(scheduler);
213
214 transport.setHttpClient(this);
215 addBean(transport);
216
217 if (resolver == null)
218 resolver = new SocketAddressResolver.Async(executor, scheduler, getAddressResolutionTimeout());
219 addBean(resolver);
220
221 handlers.put(new ContinueProtocolHandler());
222 handlers.put(new RedirectProtocolHandler(this));
223 handlers.put(new WWWAuthenticationProtocolHandler(this));
224 handlers.put(new ProxyAuthenticationProtocolHandler(this));
225
226 decoderFactories.add(new GZIPContentDecoder.Factory());
227
228 cookieManager = newCookieManager();
229 cookieStore = cookieManager.getCookieStore();
230
231 super.doStart();
232 }
233
234 private CookieManager newCookieManager()
235 {
236 return new CookieManager(getCookieStore(), CookiePolicy.ACCEPT_ALL);
237 }
238
239 @Override
240 protected void doStop() throws Exception
241 {
242 cookieStore.removeAll();
243 decoderFactories.clear();
244 handlers.clear();
245
246 for (HttpDestination destination : destinations.values())
247 destination.close();
248 destinations.clear();
249
250 requestListeners.clear();
251 authenticationStore.clearAuthentications();
252 authenticationStore.clearAuthenticationResults();
253
254 super.doStop();
255 }
256
257
258
259
260
261
262
263 public List<Request.Listener> getRequestListeners()
264 {
265 return requestListeners;
266 }
267
268
269
270
271 public CookieStore getCookieStore()
272 {
273 return cookieStore;
274 }
275
276
277
278
279 public void setCookieStore(CookieStore cookieStore)
280 {
281 this.cookieStore = Objects.requireNonNull(cookieStore);
282 this.cookieManager = newCookieManager();
283 }
284
285
286
287
288
289
290
291 CookieManager getCookieManager()
292 {
293 return cookieManager;
294 }
295
296
297
298
299 public AuthenticationStore getAuthenticationStore()
300 {
301 return authenticationStore;
302 }
303
304
305
306
307
308
309
310 public Set<ContentDecoder.Factory> getContentDecoderFactories()
311 {
312 return decoderFactories;
313 }
314
315
316
317
318
319
320
321
322
323
324
325 public ContentResponse GET(String uri) throws InterruptedException, ExecutionException, TimeoutException
326 {
327 return GET(URI.create(uri));
328 }
329
330
331
332
333
334
335
336
337
338
339
340 public ContentResponse GET(URI uri) throws InterruptedException, ExecutionException, TimeoutException
341 {
342 return newRequest(uri).send();
343 }
344
345
346
347
348
349
350
351
352
353
354
355 public ContentResponse FORM(String uri, Fields fields) throws InterruptedException, ExecutionException, TimeoutException
356 {
357 return FORM(URI.create(uri), fields);
358 }
359
360
361
362
363
364
365
366
367
368
369
370 public ContentResponse FORM(URI uri, Fields fields) throws InterruptedException, ExecutionException, TimeoutException
371 {
372 return POST(uri).content(new FormContentProvider(fields)).send();
373 }
374
375
376
377
378
379
380
381
382 public Request POST(String uri)
383 {
384 return POST(URI.create(uri));
385 }
386
387
388
389
390
391
392
393 public Request POST(URI uri)
394 {
395 return newRequest(uri).method(HttpMethod.POST);
396 }
397
398
399
400
401
402
403
404
405 public Request newRequest(String host, int port)
406 {
407 return newRequest(new Origin("http", host, port).asString());
408 }
409
410
411
412
413
414
415
416 public Request newRequest(String uri)
417 {
418 return newRequest(URI.create(uri));
419 }
420
421
422
423
424
425
426
427 public Request newRequest(URI uri)
428 {
429 return newHttpRequest(newConversation(), uri);
430 }
431
432 protected Request copyRequest(HttpRequest oldRequest, URI newURI)
433 {
434 Request newRequest = newHttpRequest(oldRequest.getConversation(), newURI);
435 newRequest.method(oldRequest.getMethod())
436 .version(oldRequest.getVersion())
437 .content(oldRequest.getContent())
438 .idleTimeout(oldRequest.getIdleTimeout(), TimeUnit.MILLISECONDS)
439 .timeout(oldRequest.getTimeout(), TimeUnit.MILLISECONDS)
440 .followRedirects(oldRequest.isFollowRedirects());
441 for (HttpField field : oldRequest.getHeaders())
442 {
443 HttpHeader header = field.getHeader();
444
445 if (HttpHeader.HOST == header)
446 continue;
447
448
449 if (HttpHeader.EXPECT == header)
450 continue;
451
452
453 if (HttpHeader.COOKIE == header)
454 continue;
455
456
457 if (HttpHeader.AUTHORIZATION == header ||
458 HttpHeader.PROXY_AUTHORIZATION == header)
459 continue;
460
461 String value = field.getValue();
462 if (!newRequest.getHeaders().contains(header, value))
463 newRequest.header(field.getName(), value);
464 }
465 return newRequest;
466 }
467
468 protected HttpRequest newHttpRequest(HttpConversation conversation, URI uri)
469 {
470 return new HttpRequest(this, conversation, uri);
471 }
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486 public Destination getDestination(String scheme, String host, int port)
487 {
488 return destinationFor(scheme, host, port);
489 }
490
491 protected HttpDestination destinationFor(String scheme, String host, int port)
492 {
493 port = normalizePort(scheme, port);
494
495 Origin origin = new Origin(scheme, host, port);
496 HttpDestination destination = destinations.get(origin);
497 if (destination == null)
498 {
499 destination = transport.newHttpDestination(origin);
500 addManaged(destination);
501 HttpDestination existing = destinations.putIfAbsent(origin, destination);
502 if (existing != null)
503 {
504 removeBean(destination);
505 destination = existing;
506 }
507 else
508 {
509 if (LOG.isDebugEnabled())
510 LOG.debug("Created {}", destination);
511 }
512 }
513 return destination;
514 }
515
516 protected boolean removeDestination(HttpDestination destination)
517 {
518 removeBean(destination);
519 return destinations.remove(destination.getOrigin()) != null;
520 }
521
522
523
524
525 public List<Destination> getDestinations()
526 {
527 return new ArrayList<Destination>(destinations.values());
528 }
529
530 protected void send(final HttpRequest request, List<Response.ResponseListener> listeners)
531 {
532 String scheme = request.getScheme().toLowerCase(Locale.ENGLISH);
533 if (!HttpScheme.HTTP.is(scheme) && !HttpScheme.HTTPS.is(scheme))
534 throw new IllegalArgumentException("Invalid protocol " + scheme);
535
536 String host = request.getHost().toLowerCase(Locale.ENGLISH);
537 HttpDestination destination = destinationFor(scheme, host, request.getPort());
538 destination.send(request, listeners);
539 }
540
541 protected void newConnection(final HttpDestination destination, final Promise<Connection> promise)
542 {
543 Origin.Address address = destination.getConnectAddress();
544 resolver.resolve(address.getHost(), address.getPort(), new Promise<List<InetSocketAddress>>()
545 {
546 @Override
547 public void succeeded(List<InetSocketAddress> socketAddresses)
548 {
549 Map<String, Object> context = new HashMap<>();
550 context.put(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY, destination);
551 connect(socketAddresses, 0, context);
552 }
553
554 @Override
555 public void failed(Throwable x)
556 {
557 promise.failed(x);
558 }
559
560 private void connect(List<InetSocketAddress> socketAddresses, int index, Map<String, Object> context)
561 {
562 context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, new Promise<Connection>()
563 {
564 @Override
565 public void succeeded(Connection result)
566 {
567 promise.succeeded(result);
568 }
569
570 @Override
571 public void failed(Throwable x)
572 {
573 int nextIndex = index + 1;
574 if (nextIndex == socketAddresses.size())
575 promise.failed(x);
576 else
577 connect(socketAddresses, nextIndex, context);
578 }
579 });
580 transport.connect(socketAddresses.get(index), context);
581 }
582 });
583 }
584
585 private HttpConversation newConversation()
586 {
587 return new HttpConversation();
588 }
589
590 public ProtocolHandlers getProtocolHandlers()
591 {
592 return handlers;
593 }
594
595 protected ProtocolHandler findProtocolHandler(Request request, Response response)
596 {
597 return handlers.find(request, response);
598 }
599
600
601
602
603 public ByteBufferPool getByteBufferPool()
604 {
605 return byteBufferPool;
606 }
607
608
609
610
611 public void setByteBufferPool(ByteBufferPool byteBufferPool)
612 {
613 this.byteBufferPool = byteBufferPool;
614 }
615
616
617
618
619 @ManagedAttribute("The timeout, in milliseconds, for connect() operations")
620 public long getConnectTimeout()
621 {
622 return connectTimeout;
623 }
624
625
626
627
628
629 public void setConnectTimeout(long connectTimeout)
630 {
631 this.connectTimeout = connectTimeout;
632 }
633
634
635
636
637
638 public long getAddressResolutionTimeout()
639 {
640 return addressResolutionTimeout;
641 }
642
643
644
645
646
647
648
649
650
651
652 public void setAddressResolutionTimeout(long addressResolutionTimeout)
653 {
654 this.addressResolutionTimeout = addressResolutionTimeout;
655 }
656
657
658
659
660 @ManagedAttribute("The timeout, in milliseconds, to close idle connections")
661 public long getIdleTimeout()
662 {
663 return idleTimeout;
664 }
665
666
667
668
669 public void setIdleTimeout(long idleTimeout)
670 {
671 this.idleTimeout = idleTimeout;
672 }
673
674
675
676
677
678 public SocketAddress getBindAddress()
679 {
680 return bindAddress;
681 }
682
683
684
685
686
687
688 public void setBindAddress(SocketAddress bindAddress)
689 {
690 this.bindAddress = bindAddress;
691 }
692
693
694
695
696 public HttpField getUserAgentField()
697 {
698 return agentField;
699 }
700
701
702
703
704 public void setUserAgentField(HttpField agent)
705 {
706 if (agent.getHeader() != HttpHeader.USER_AGENT)
707 throw new IllegalArgumentException();
708 this.agentField = agent;
709 }
710
711
712
713
714
715 @ManagedAttribute("Whether HTTP redirects are followed")
716 public boolean isFollowRedirects()
717 {
718 return followRedirects;
719 }
720
721
722
723
724
725 public void setFollowRedirects(boolean follow)
726 {
727 this.followRedirects = follow;
728 }
729
730
731
732
733 public Executor getExecutor()
734 {
735 return executor;
736 }
737
738
739
740
741 public void setExecutor(Executor executor)
742 {
743 this.executor = executor;
744 }
745
746
747
748
749 public Scheduler getScheduler()
750 {
751 return scheduler;
752 }
753
754
755
756
757 public void setScheduler(Scheduler scheduler)
758 {
759 this.scheduler = scheduler;
760 }
761
762
763
764
765 public SocketAddressResolver getSocketAddressResolver()
766 {
767 return resolver;
768 }
769
770
771
772
773 public void setSocketAddressResolver(SocketAddressResolver resolver)
774 {
775 this.resolver = resolver;
776 }
777
778
779
780
781 @ManagedAttribute("The max number of connections per each destination")
782 public int getMaxConnectionsPerDestination()
783 {
784 return maxConnectionsPerDestination;
785 }
786
787
788
789
790
791
792
793
794
795
796
797
798 public void setMaxConnectionsPerDestination(int maxConnectionsPerDestination)
799 {
800 this.maxConnectionsPerDestination = maxConnectionsPerDestination;
801 }
802
803
804
805
806 @ManagedAttribute("The max number of requests queued per each destination")
807 public int getMaxRequestsQueuedPerDestination()
808 {
809 return maxRequestsQueuedPerDestination;
810 }
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825 public void setMaxRequestsQueuedPerDestination(int maxRequestsQueuedPerDestination)
826 {
827 this.maxRequestsQueuedPerDestination = maxRequestsQueuedPerDestination;
828 }
829
830
831
832
833 @ManagedAttribute("The request buffer size")
834 public int getRequestBufferSize()
835 {
836 return requestBufferSize;
837 }
838
839
840
841
842 public void setRequestBufferSize(int requestBufferSize)
843 {
844 this.requestBufferSize = requestBufferSize;
845 }
846
847
848
849
850 @ManagedAttribute("The response buffer size")
851 public int getResponseBufferSize()
852 {
853 return responseBufferSize;
854 }
855
856
857
858
859 public void setResponseBufferSize(int responseBufferSize)
860 {
861 this.responseBufferSize = responseBufferSize;
862 }
863
864
865
866
867
868 public int getMaxRedirects()
869 {
870 return maxRedirects;
871 }
872
873
874
875
876
877 public void setMaxRedirects(int maxRedirects)
878 {
879 this.maxRedirects = maxRedirects;
880 }
881
882
883
884
885 @ManagedAttribute(value = "Whether the TCP_NODELAY option is enabled", name = "tcpNoDelay")
886 public boolean isTCPNoDelay()
887 {
888 return tcpNoDelay;
889 }
890
891
892
893
894
895 public void setTCPNoDelay(boolean tcpNoDelay)
896 {
897 this.tcpNoDelay = tcpNoDelay;
898 }
899
900
901
902
903
904 @Deprecated
905 public boolean isDispatchIO()
906 {
907
908 return false;
909 }
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924 @Deprecated
925 public void setDispatchIO(boolean dispatchIO)
926 {
927 }
928
929
930
931
932
933 @ManagedAttribute("Whether request/response events must be strictly ordered")
934 public boolean isStrictEventOrdering()
935 {
936 return strictEventOrdering;
937 }
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965 public void setStrictEventOrdering(boolean strictEventOrdering)
966 {
967 this.strictEventOrdering = strictEventOrdering;
968 }
969
970
971
972
973
974 @ManagedAttribute("Whether idle destinations are removed")
975 public boolean isRemoveIdleDestinations()
976 {
977 return removeIdleDestinations;
978 }
979
980
981
982
983
984
985
986
987
988
989
990
991
992 public void setRemoveIdleDestinations(boolean removeIdleDestinations)
993 {
994 this.removeIdleDestinations = removeIdleDestinations;
995 }
996
997
998
999
1000 @ManagedAttribute("Whether the connect() operation is blocking")
1001 public boolean isConnectBlocking()
1002 {
1003 return connectBlocking;
1004 }
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 public void setConnectBlocking(boolean connectBlocking)
1017 {
1018 this.connectBlocking = connectBlocking;
1019 }
1020
1021
1022
1023
1024 public ProxyConfiguration getProxyConfiguration()
1025 {
1026 return proxyConfig;
1027 }
1028
1029 protected HttpField getAcceptEncodingField()
1030 {
1031 return encodingField;
1032 }
1033
1034 protected String normalizeHost(String host)
1035 {
1036 if (host != null && host.matches("\\[.*\\]"))
1037 return host.substring(1, host.length() - 1);
1038 return host;
1039 }
1040
1041 protected int normalizePort(String scheme, int port)
1042 {
1043 return port > 0 ? port : HttpScheme.HTTPS.is(scheme) ? 443 : 80;
1044 }
1045
1046 public boolean isDefaultPort(String scheme, int port)
1047 {
1048 return HttpScheme.HTTPS.is(scheme) ? port == 443 : port == 80;
1049 }
1050
1051 private class ContentDecoderFactorySet implements Set<ContentDecoder.Factory>
1052 {
1053 private final Set<ContentDecoder.Factory> set = new HashSet<>();
1054
1055 @Override
1056 public boolean add(ContentDecoder.Factory e)
1057 {
1058 boolean result = set.add(e);
1059 invalidate();
1060 return result;
1061 }
1062
1063 @Override
1064 public boolean addAll(Collection<? extends ContentDecoder.Factory> c)
1065 {
1066 boolean result = set.addAll(c);
1067 invalidate();
1068 return result;
1069 }
1070
1071 @Override
1072 public boolean remove(Object o)
1073 {
1074 boolean result = set.remove(o);
1075 invalidate();
1076 return result;
1077 }
1078
1079 @Override
1080 public boolean removeAll(Collection<?> c)
1081 {
1082 boolean result = set.removeAll(c);
1083 invalidate();
1084 return result;
1085 }
1086
1087 @Override
1088 public boolean retainAll(Collection<?> c)
1089 {
1090 boolean result = set.retainAll(c);
1091 invalidate();
1092 return result;
1093 }
1094
1095 @Override
1096 public void clear()
1097 {
1098 set.clear();
1099 invalidate();
1100 }
1101
1102 @Override
1103 public int size()
1104 {
1105 return set.size();
1106 }
1107
1108 @Override
1109 public boolean isEmpty()
1110 {
1111 return set.isEmpty();
1112 }
1113
1114 @Override
1115 public boolean contains(Object o)
1116 {
1117 return set.contains(o);
1118 }
1119
1120 @Override
1121 public boolean containsAll(Collection<?> c)
1122 {
1123 return set.containsAll(c);
1124 }
1125
1126 @Override
1127 public Iterator<ContentDecoder.Factory> iterator()
1128 {
1129 final Iterator<ContentDecoder.Factory> iterator = set.iterator();
1130 return new Iterator<ContentDecoder.Factory>()
1131 {
1132 @Override
1133 public boolean hasNext()
1134 {
1135 return iterator.hasNext();
1136 }
1137
1138 @Override
1139 public ContentDecoder.Factory next()
1140 {
1141 return iterator.next();
1142 }
1143
1144 @Override
1145 public void remove()
1146 {
1147 iterator.remove();
1148 invalidate();
1149 }
1150 };
1151 }
1152
1153 @Override
1154 public Object[] toArray()
1155 {
1156 return set.toArray();
1157 }
1158
1159 @Override
1160 public <T> T[] toArray(T[] a)
1161 {
1162 return set.toArray(a);
1163 }
1164
1165 private void invalidate()
1166 {
1167 if (set.isEmpty())
1168 {
1169 encodingField = null;
1170 }
1171 else
1172 {
1173 StringBuilder value = new StringBuilder();
1174 for (Iterator<ContentDecoder.Factory> iterator = set.iterator(); iterator.hasNext();)
1175 {
1176 ContentDecoder.Factory decoderFactory = iterator.next();
1177 value.append(decoderFactory.getEncoding());
1178 if (iterator.hasNext())
1179 value.append(",");
1180 }
1181 encodingField = new HttpField(HttpHeader.ACCEPT_ENCODING, value.toString());
1182 }
1183 }
1184 }
1185 }