View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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  /**
31   * <p>A protocol handler that handles the 100 response code.</p>
32   */
33  public class ContinueProtocolHandler implements ProtocolHandler
34  {
35      public static final String NAME = "continue";
36      private static final String ATTRIBUTE = ContinueProtocolHandler.class.getName() + ".100continue";
37  
38      private final ResponseNotifier notifier;
39  
40      public ContinueProtocolHandler()
41      {
42          this.notifier = new ResponseNotifier();
43      }
44  
45      @Override
46      public String getName()
47      {
48          return NAME;
49      }
50  
51      @Override
52      public boolean accept(Request request, Response response)
53      {
54          boolean expect100 = request.getHeaders().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
55          HttpConversation conversation = ((HttpRequest)request).getConversation();
56          boolean handled100 = conversation.getAttribute(ATTRIBUTE) != null;
57          return expect100 && !handled100;
58      }
59  
60      @Override
61      public Response.Listener getResponseListener()
62      {
63          // Return new instances every time to keep track of the response content
64          return new ContinueListener();
65      }
66  
67      protected class ContinueListener extends BufferingResponseListener
68      {
69          @Override
70          public void onSuccess(Response response)
71          {
72              // Handling of success must be done here and not from onComplete(),
73              // since the onComplete() is not invoked because the request is not completed yet.
74  
75              HttpConversation conversation = ((HttpRequest)response.getRequest()).getConversation();
76              // Mark the 100 Continue response as handled
77              conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
78  
79              // Reset the conversation listeners, since we are going to receive another response code
80              conversation.updateResponseListeners(null);
81  
82              HttpExchange exchange = conversation.getExchanges().peekLast();
83              assert exchange.getResponse() == response;
84              switch (response.getStatus())
85              {
86                  case 100:
87                  {
88                      // All good, continue
89                      exchange.resetResponse();
90                      exchange.proceed(null);
91                      break;
92                  }
93                  default:
94                  {
95                      // Server either does not support 100 Continue,
96                      // or it does and wants to refuse the request content,
97                      // or we got some other HTTP status code like a redirect.
98                      List<Response.ResponseListener> listeners = exchange.getResponseListeners();
99                      HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
100                     notifier.forwardSuccess(listeners, contentResponse);
101                     exchange.proceed(new HttpRequestException("Expectation failed", exchange.getRequest()));
102                     break;
103                 }
104             }
105         }
106 
107         @Override
108         public void onFailure(Response response, Throwable failure)
109         {
110             HttpConversation conversation = ((HttpRequest)response.getRequest()).getConversation();
111             // Mark the 100 Continue response as handled
112             conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
113             // Reset the conversation listeners to allow the conversation to be completed
114             conversation.updateResponseListeners(null);
115 
116             HttpExchange exchange = conversation.getExchanges().peekLast();
117             assert exchange.getResponse() == response;
118             List<Response.ResponseListener> listeners = exchange.getResponseListeners();
119             HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
120             notifier.forwardFailureComplete(listeners, exchange.getRequest(), exchange.getRequestFailure(), contentResponse, failure);
121         }
122 
123         @Override
124         public void onComplete(Result result)
125         {
126         }
127     }
128 }