1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.client.http;
20
21 import java.nio.channels.AsynchronousCloseException;
22 import java.util.concurrent.TimeoutException;
23 import java.util.concurrent.atomic.AtomicBoolean;
24
25 import org.eclipse.jetty.client.HttpConnection;
26 import org.eclipse.jetty.client.HttpDestination;
27 import org.eclipse.jetty.client.HttpExchange;
28 import org.eclipse.jetty.client.api.Connection;
29 import org.eclipse.jetty.client.api.Request;
30 import org.eclipse.jetty.client.api.Response;
31 import org.eclipse.jetty.io.AbstractConnection;
32 import org.eclipse.jetty.io.EndPoint;
33 import org.eclipse.jetty.util.log.Log;
34 import org.eclipse.jetty.util.log.Logger;
35
36 public class HttpConnectionOverHTTP extends AbstractConnection implements Connection
37 {
38 private static final Logger LOG = Log.getLogger(HttpConnectionOverHTTP.class);
39
40 private final AtomicBoolean closed = new AtomicBoolean();
41 private final Delegate delegate;
42 private final HttpChannelOverHTTP channel;
43 private long idleTimeout;
44
45 public HttpConnectionOverHTTP(EndPoint endPoint, HttpDestination destination)
46 {
47 super(endPoint, destination.getHttpClient().getExecutor(), destination.getHttpClient().isDispatchIO());
48 this.delegate = new Delegate(destination);
49 this.channel = new HttpChannelOverHTTP(this);
50 }
51
52 public HttpChannelOverHTTP getHttpChannel()
53 {
54 return channel;
55 }
56
57 public HttpDestinationOverHTTP getHttpDestination()
58 {
59 return (HttpDestinationOverHTTP)delegate.getHttpDestination();
60 }
61
62 @Override
63 public void send(Request request, Response.CompleteListener listener)
64 {
65 delegate.send(request, listener);
66 }
67
68 protected void send(HttpExchange exchange)
69 {
70 delegate.send(exchange);
71 }
72
73 @Override
74 public void onOpen()
75 {
76 super.onOpen();
77 fillInterested();
78 }
79
80 public boolean isClosed()
81 {
82 return closed.get();
83 }
84
85 @Override
86 protected boolean onReadTimeout()
87 {
88 if (LOG.isDebugEnabled())
89 LOG.debug("{} idle timeout", this);
90 close(new TimeoutException());
91 return false;
92 }
93
94 @Override
95 public void onFillable()
96 {
97 HttpExchange exchange = channel.getHttpExchange();
98 if (exchange != null)
99 {
100 channel.receive();
101 }
102 else
103 {
104
105
106 close();
107 }
108 }
109
110 public void release()
111 {
112
113 getEndPoint().setIdleTimeout(idleTimeout);
114 getHttpDestination().release(this);
115 }
116
117 @Override
118 public void close()
119 {
120 close(new AsynchronousCloseException());
121 }
122
123 protected void close(Throwable failure)
124 {
125 if (softClose())
126 {
127
128
129 getHttpDestination().close(this);
130 getEndPoint().shutdownOutput();
131 if (LOG.isDebugEnabled())
132 LOG.debug("{} oshut", this);
133 getEndPoint().close();
134 if (LOG.isDebugEnabled())
135 LOG.debug("{} closed", this);
136
137 abort(failure);
138 }
139 }
140
141 public boolean softClose()
142 {
143 return closed.compareAndSet(false, true);
144 }
145
146 private boolean abort(Throwable failure)
147 {
148 HttpExchange exchange = channel.getHttpExchange();
149 return exchange != null && exchange.getRequest().abort(failure);
150 }
151
152 @Override
153 public String toString()
154 {
155 return String.format("%s@%h(l:%s <-> r:%s)",
156 getClass().getSimpleName(),
157 this,
158 getEndPoint().getLocalAddress(),
159 getEndPoint().getRemoteAddress());
160 }
161
162 private class Delegate extends HttpConnection
163 {
164 private Delegate(HttpDestination destination)
165 {
166 super(destination);
167 }
168
169 @Override
170 protected void send(HttpExchange exchange)
171 {
172 Request request = exchange.getRequest();
173 normalizeRequest(request);
174
175
176 EndPoint endPoint = getEndPoint();
177 idleTimeout = endPoint.getIdleTimeout();
178 endPoint.setIdleTimeout(request.getIdleTimeout());
179
180
181 channel.associate(exchange);
182 channel.send();
183 }
184
185 @Override
186 public void close()
187 {
188 HttpConnectionOverHTTP.this.close();
189 }
190
191 @Override
192 public String toString()
193 {
194 return HttpConnectionOverHTTP.this.toString();
195 }
196 }
197 }