View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.client;
20  
21  import java.util.List;
22  
23  import org.eclipse.jetty.client.api.Request;
24  import org.eclipse.jetty.client.api.Response;
25  import org.eclipse.jetty.client.api.Result;
26  import org.eclipse.jetty.client.util.BufferingResponseListener;
27  import org.eclipse.jetty.http.HttpHeader;
28  import org.eclipse.jetty.http.HttpHeaderValue;
29  
30  public class ContinueProtocolHandler implements ProtocolHandler
31  {
32      private static final String ATTRIBUTE = ContinueProtocolHandler.class.getName() + ".100continue";
33  
34      private final HttpClient client;
35      private final ResponseNotifier notifier;
36  
37      public ContinueProtocolHandler(HttpClient client)
38      {
39          this.client = client;
40          this.notifier = new ResponseNotifier(client);
41      }
42  
43      @Override
44      public boolean accept(Request request, Response response)
45      {
46          boolean expect100 = request.getHeaders().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
47          HttpConversation conversation = client.getConversation(request.getConversationID(), false);
48          boolean handled100 = conversation != null && conversation.getAttribute(ATTRIBUTE) != null;
49          return expect100 && !handled100;
50      }
51  
52      @Override
53      public Response.Listener getResponseListener()
54      {
55          // Return new instances every time to keep track of the response content
56          return new ContinueListener();
57      }
58  
59      protected class ContinueListener extends BufferingResponseListener
60      {
61          @Override
62          public void onSuccess(Response response)
63          {
64              // Handling of success must be done here and not from onComplete(),
65              // since the onComplete() is not invoked because the request is not completed yet.
66  
67              HttpConversation conversation = client.getConversation(response.getConversationID(), false);
68              // Mark the 100 Continue response as handled
69              conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
70  
71              // Reset the conversation listeners, since we are going to receive another response code
72              conversation.updateResponseListeners(null);
73  
74              HttpExchange exchange = conversation.getExchanges().peekLast();
75              assert exchange.getResponse() == response;
76              switch (response.getStatus())
77              {
78                  case 100:
79                  {
80                      // All good, continue
81                      exchange.resetResponse(true);
82                      exchange.proceed(true);
83                      break;
84                  }
85                  default:
86                  {
87                      // Server either does not support 100 Continue,
88                      // or it does and wants to refuse the request content,
89                      // or we got some other HTTP status code like a redirect.
90                      List<Response.ResponseListener> listeners = exchange.getResponseListeners();
91                      HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getEncoding());
92                      notifier.forwardSuccess(listeners, contentResponse);
93                      exchange.proceed(false);
94                      break;
95                  }
96              }
97          }
98  
99          @Override
100         public void onFailure(Response response, Throwable failure)
101         {
102             HttpConversation conversation = client.getConversation(response.getConversationID(), false);
103             // Mark the 100 Continue response as handled
104             conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
105             // Reset the conversation listeners to allow the conversation to be completed
106             conversation.updateResponseListeners(null);
107 
108             HttpExchange exchange = conversation.getExchanges().peekLast();
109             assert exchange.getResponse() == response;
110             List<Response.ResponseListener> listeners = exchange.getResponseListeners();
111             HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getEncoding());
112             notifier.forwardFailureComplete(listeners, exchange.getRequest(), exchange.getRequestFailure(), contentResponse, failure);
113         }
114 
115         @Override
116         public void onComplete(Result result)
117         {
118         }
119     }
120 }