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 void onContinue(Request request)
68      {
69      }
70  
71      protected class ContinueListener extends BufferingResponseListener
72      {
73          @Override
74          public void onSuccess(Response response)
75          {
76              // Handling of success must be done here and not from onComplete(),
77              // since the onComplete() is not invoked because the request is not completed yet.
78  
79              Request request = response.getRequest();
80              HttpConversation conversation = ((HttpRequest)request).getConversation();
81              // Mark the 100 Continue response as handled
82              conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
83  
84              // Reset the conversation listeners, since we are going to receive another response code
85              conversation.updateResponseListeners(null);
86  
87              HttpExchange exchange = conversation.getExchanges().peekLast();
88              assert exchange.getResponse() == response;
89              switch (response.getStatus())
90              {
91                  case 100:
92                  {
93                      // All good, continue
94                      exchange.resetResponse();
95                      exchange.proceed(null);
96                      onContinue(request);
97                      break;
98                  }
99                  default:
100                 {
101                     // Server either does not support 100 Continue,
102                     // or it does and wants to refuse the request content,
103                     // or we got some other HTTP status code like a redirect.
104                     List<Response.ResponseListener> listeners = exchange.getResponseListeners();
105                     HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
106                     notifier.forwardSuccess(listeners, contentResponse);
107                     exchange.proceed(new HttpRequestException("Expectation failed", request));
108                     break;
109                 }
110             }
111         }
112 
113         @Override
114         public void onFailure(Response response, Throwable failure)
115         {
116             HttpConversation conversation = ((HttpRequest)response.getRequest()).getConversation();
117             // Mark the 100 Continue response as handled
118             conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
119             // Reset the conversation listeners to allow the conversation to be completed
120             conversation.updateResponseListeners(null);
121 
122             HttpExchange exchange = conversation.getExchanges().peekLast();
123             assert exchange.getResponse() == response;
124             List<Response.ResponseListener> listeners = exchange.getResponseListeners();
125             HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
126             notifier.forwardFailureComplete(listeners, exchange.getRequest(), exchange.getRequestFailure(), contentResponse, failure);
127         }
128 
129         @Override
130         public void onComplete(Result result)
131         {
132         }
133     }
134 }