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.http;
20  
21  import java.util.concurrent.TimeoutException;
22  
23  import org.eclipse.jetty.client.HttpConnection;
24  import org.eclipse.jetty.client.HttpDestination;
25  import org.eclipse.jetty.client.HttpExchange;
26  import org.eclipse.jetty.client.api.Connection;
27  import org.eclipse.jetty.client.api.Request;
28  import org.eclipse.jetty.client.api.Response;
29  import org.eclipse.jetty.io.AbstractConnection;
30  import org.eclipse.jetty.io.EndPoint;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.log.Logger;
33  
34  public class HttpConnectionOverHTTP extends AbstractConnection implements Connection
35  {
36      private static final Logger LOG = Log.getLogger(HttpConnectionOverHTTP.class);
37  
38      private final Delegate delegate;
39      private final HttpChannelOverHTTP channel;
40      private boolean closed;
41      private long idleTimeout;
42  
43      public HttpConnectionOverHTTP(EndPoint endPoint, HttpDestination destination)
44      {
45          super(endPoint, destination.getHttpClient().getExecutor(), destination.getHttpClient().isDispatchIO());
46          this.delegate = new Delegate(destination);
47          this.channel = new HttpChannelOverHTTP(this);
48      }
49  
50      public HttpChannelOverHTTP getHttpChannel()
51      {
52          return channel;
53      }
54  
55      public HttpDestinationOverHTTP getHttpDestination()
56      {
57          return (HttpDestinationOverHTTP)delegate.getHttpDestination();
58      }
59  
60      @Override
61      public void send(Request request, Response.CompleteListener listener)
62      {
63          delegate.send(request, listener);
64      }
65  
66      protected void send(HttpExchange exchange)
67      {
68          delegate.send(exchange);
69      }
70  
71      @Override
72      public void onOpen()
73      {
74          super.onOpen();
75          fillInterested();
76      }
77  
78      @Override
79      public void onClose()
80      {
81          closed = true;
82          super.onClose();
83      }
84  
85      protected boolean isClosed()
86      {
87          return closed;
88      }
89  
90      @Override
91      protected boolean onReadTimeout()
92      {
93          LOG.debug("{} idle timeout", this);
94  
95          HttpExchange exchange = channel.getHttpExchange();
96          if (exchange != null)
97              return exchange.getRequest().abort(new TimeoutException());
98  
99          getHttpDestination().close(this);
100         return true;
101     }
102 
103     @Override
104     public void onFillable()
105     {
106         HttpExchange exchange = channel.getHttpExchange();
107         if (exchange != null)
108         {
109             channel.receive();
110         }
111         else
112         {
113             // If there is no exchange, then could be either a remote close,
114             // or garbage bytes; in both cases we close the connection
115             close();
116         }
117     }
118 
119     public void release()
120     {
121         // Restore idle timeout
122         getEndPoint().setIdleTimeout(idleTimeout);
123         getHttpDestination().release(this);
124     }
125 
126     @Override
127     public void close()
128     {
129         getHttpDestination().close(this);
130         getEndPoint().shutdownOutput();
131         LOG.debug("{} oshut", this);
132         getEndPoint().close();
133         LOG.debug("{} closed", this);
134     }
135 
136     @Override
137     public String toString()
138     {
139         return String.format("%s@%h(l:%s <-> r:%s)",
140                 getClass().getSimpleName(),
141                 this,
142                 getEndPoint().getLocalAddress(),
143                 getEndPoint().getRemoteAddress());
144     }
145 
146     private class Delegate extends HttpConnection
147     {
148         private Delegate(HttpDestination destination)
149         {
150             super(destination);
151         }
152 
153         @Override
154         protected void send(HttpExchange exchange)
155         {
156             Request request = exchange.getRequest();
157             normalizeRequest(request);
158 
159             // Save the old idle timeout to restore it
160             EndPoint endPoint = getEndPoint();
161             idleTimeout = endPoint.getIdleTimeout();
162             endPoint.setIdleTimeout(request.getIdleTimeout());
163 
164             // One channel per connection, just delegate the send
165             channel.associate(exchange);
166             channel.send();
167         }
168 
169         @Override
170         public void close()
171         {
172             HttpConnectionOverHTTP.this.close();
173         }
174 
175         @Override
176         public String toString()
177         {
178             return HttpConnectionOverHTTP.this.toString();
179         }
180     }
181 }