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.io.IOException;
22 import java.net.URI;
23 import java.nio.ByteBuffer;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.atomic.AtomicReference;
30
31 import org.eclipse.jetty.client.api.Response;
32 import org.eclipse.jetty.client.api.Result;
33 import org.eclipse.jetty.http.HttpField;
34 import org.eclipse.jetty.http.HttpHeader;
35 import org.eclipse.jetty.util.BufferUtil;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
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 public abstract class HttpReceiver
66 {
67 protected static final Logger LOG = Log.getLogger(HttpReceiver.class);
68
69 private final AtomicReference<ResponseState> responseState = new AtomicReference<>(ResponseState.IDLE);
70 private final HttpChannel channel;
71 private volatile ContentDecoder decoder;
72
73 protected HttpReceiver(HttpChannel channel)
74 {
75 this.channel = channel;
76 }
77
78 protected HttpChannel getHttpChannel()
79 {
80 return channel;
81 }
82
83 protected HttpExchange getHttpExchange()
84 {
85 return channel.getHttpExchange();
86 }
87
88 protected HttpDestination getHttpDestination()
89 {
90 return channel.getHttpDestination();
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104 protected boolean responseBegin(HttpExchange exchange)
105 {
106 if (!updateResponseState(ResponseState.IDLE, ResponseState.BEGIN))
107 return false;
108
109 HttpConversation conversation = exchange.getConversation();
110 HttpResponse response = exchange.getResponse();
111
112 HttpDestination destination = getHttpDestination();
113 HttpClient client = destination.getHttpClient();
114 ProtocolHandler protocolHandler = client.findProtocolHandler(exchange.getRequest(), response);
115 Response.Listener handlerListener = null;
116 if (protocolHandler != null)
117 {
118 handlerListener = protocolHandler.getResponseListener();
119 LOG.debug("Found protocol handler {}", protocolHandler);
120 }
121 exchange.getConversation().updateResponseListeners(handlerListener);
122
123 LOG.debug("Response begin {}", response);
124 ResponseNotifier notifier = destination.getResponseNotifier();
125 notifier.notifyBegin(conversation.getResponseListeners(), response);
126
127 return true;
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142 protected boolean responseHeader(HttpExchange exchange, HttpField field)
143 {
144 out: while (true)
145 {
146 ResponseState current = responseState.get();
147 switch (current)
148 {
149 case BEGIN:
150 case HEADER:
151 {
152 if (updateResponseState(current, ResponseState.HEADER))
153 break out;
154 break;
155 }
156 default:
157 {
158 return false;
159 }
160 }
161 }
162
163 HttpResponse response = exchange.getResponse();
164 ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
165 boolean process = notifier.notifyHeader(exchange.getConversation().getResponseListeners(), response, field);
166 if (process)
167 {
168 response.getHeaders().add(field);
169 HttpHeader fieldHeader = field.getHeader();
170 if (fieldHeader != null)
171 {
172 switch (fieldHeader)
173 {
174 case SET_COOKIE:
175 case SET_COOKIE2:
176 {
177 storeCookie(exchange.getRequest().getURI(), field);
178 break;
179 }
180 default:
181 {
182 break;
183 }
184 }
185 }
186 }
187
188 return true;
189 }
190
191 protected void storeCookie(URI uri, HttpField field)
192 {
193 try
194 {
195 String value = field.getValue();
196 if (value != null)
197 {
198 Map<String, List<String>> header = new HashMap<>(1);
199 header.put(field.getHeader().asString(), Collections.singletonList(value));
200 getHttpDestination().getHttpClient().getCookieManager().put(uri, header);
201 }
202 }
203 catch (IOException x)
204 {
205 LOG.debug(x);
206 }
207 }
208
209
210
211
212
213
214
215
216
217 protected boolean responseHeaders(HttpExchange exchange)
218 {
219 out: while (true)
220 {
221 ResponseState current = responseState.get();
222 switch (current)
223 {
224 case BEGIN:
225 case HEADER:
226 {
227 if (updateResponseState(current, ResponseState.HEADERS))
228 break out;
229 break;
230 }
231 default:
232 {
233 return false;
234 }
235 }
236 }
237
238 HttpResponse response = exchange.getResponse();
239 if (LOG.isDebugEnabled())
240 LOG.debug("Response headers {}{}{}", response, System.getProperty("line.separator"), response.getHeaders().toString().trim());
241 ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
242 notifier.notifyHeaders(exchange.getConversation().getResponseListeners(), response);
243
244 Enumeration<String> contentEncodings = response.getHeaders().getValues(HttpHeader.CONTENT_ENCODING.asString(), ",");
245 if (contentEncodings != null)
246 {
247 for (ContentDecoder.Factory factory : getHttpDestination().getHttpClient().getContentDecoderFactories())
248 {
249 while (contentEncodings.hasMoreElements())
250 {
251 if (factory.getEncoding().equalsIgnoreCase(contentEncodings.nextElement()))
252 {
253 this.decoder = factory.newContentDecoder();
254 break;
255 }
256 }
257 }
258 }
259
260 return true;
261 }
262
263
264
265
266
267
268
269
270
271
272 protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer)
273 {
274 out: while (true)
275 {
276 ResponseState current = responseState.get();
277 switch (current)
278 {
279 case HEADERS:
280 case CONTENT:
281 {
282 if (updateResponseState(current, ResponseState.CONTENT))
283 break out;
284 break;
285 }
286 default:
287 {
288 return false;
289 }
290 }
291 }
292
293 HttpResponse response = exchange.getResponse();
294 if (LOG.isDebugEnabled())
295 LOG.debug("Response content {}{}{}", response, System.getProperty("line.separator"), BufferUtil.toDetailString(buffer));
296
297 ContentDecoder decoder = this.decoder;
298 if (decoder != null)
299 {
300 buffer = decoder.decode(buffer);
301 if (LOG.isDebugEnabled())
302 LOG.debug("Response content decoded ({}) {}{}{}", decoder, response, System.getProperty("line.separator"), BufferUtil.toDetailString(buffer));
303 }
304
305 ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
306 notifier.notifyContent(exchange.getConversation().getResponseListeners(), response, buffer);
307
308 return true;
309 }
310
311
312
313
314
315
316
317
318
319
320 protected boolean responseSuccess(HttpExchange exchange)
321 {
322
323
324 boolean completed = exchange.responseComplete();
325 if (!completed)
326 return false;
327
328
329 reset();
330
331
332
333
334
335
336 Result result = exchange.terminateResponse(null);
337
338 HttpResponse response = exchange.getResponse();
339 LOG.debug("Response success {}", response);
340 List<Response.ResponseListener> listeners = exchange.getConversation().getResponseListeners();
341 ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
342 notifier.notifySuccess(listeners, response);
343
344 if (result != null)
345 {
346 boolean ordered = getHttpDestination().getHttpClient().isStrictEventOrdering();
347 if (!ordered)
348 channel.exchangeTerminated(result);
349 LOG.debug("Request/Response succeeded {}", response);
350 notifier.notifyComplete(listeners, result);
351 if (ordered)
352 channel.exchangeTerminated(result);
353 }
354
355 return true;
356 }
357
358
359
360
361
362
363
364
365
366 protected boolean responseFailure(Throwable failure)
367 {
368 HttpExchange exchange = getHttpExchange();
369
370
371
372
373 if (exchange == null)
374 return false;
375
376
377
378 boolean completed = exchange.responseComplete();
379 if (!completed)
380 return false;
381
382
383 dispose();
384
385
386
387 Result result = exchange.terminateResponse(failure);
388
389 HttpResponse response = exchange.getResponse();
390 LOG.debug("Response failure {} {}", response, failure);
391 List<Response.ResponseListener> listeners = exchange.getConversation().getResponseListeners();
392 ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
393 notifier.notifyFailure(listeners, response, failure);
394
395 if (result != null)
396 {
397 boolean ordered = getHttpDestination().getHttpClient().isStrictEventOrdering();
398 if (!ordered)
399 channel.exchangeTerminated(result);
400 LOG.debug("Request/Response failed {}", response);
401 notifier.notifyComplete(listeners, result);
402 if (ordered)
403 channel.exchangeTerminated(result);
404 }
405
406 return true;
407 }
408
409
410
411
412
413
414
415
416 protected void reset()
417 {
418 decoder = null;
419 responseState.set(ResponseState.IDLE);
420 }
421
422
423
424
425
426
427
428
429 protected void dispose()
430 {
431 decoder = null;
432 responseState.set(ResponseState.FAILURE);
433 }
434
435 public boolean abort(Throwable cause)
436 {
437 return responseFailure(cause);
438 }
439
440 private boolean updateResponseState(ResponseState from, ResponseState to)
441 {
442 boolean updated = responseState.compareAndSet(from, to);
443 if (!updated)
444 LOG.debug("State update failed: {} -> {}: {}", from, to, responseState.get());
445 return updated;
446 }
447
448
449
450
451 private enum ResponseState
452 {
453
454
455
456 IDLE,
457
458
459
460 BEGIN,
461
462
463
464 HEADER,
465
466
467
468 HEADERS,
469
470
471
472 CONTENT,
473
474
475
476 FAILURE
477 }
478 }