1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http2.client.http;
20
21 import java.nio.channels.AsynchronousCloseException;
22 import java.util.Set;
23 import java.util.concurrent.TimeoutException;
24 import java.util.concurrent.atomic.AtomicBoolean;
25
26 import org.eclipse.jetty.client.HttpChannel;
27 import org.eclipse.jetty.client.HttpConnection;
28 import org.eclipse.jetty.client.HttpDestination;
29 import org.eclipse.jetty.client.HttpExchange;
30 import org.eclipse.jetty.client.SendFailure;
31 import org.eclipse.jetty.http.HttpVersion;
32 import org.eclipse.jetty.http2.ErrorCode;
33 import org.eclipse.jetty.http2.api.Session;
34 import org.eclipse.jetty.util.Callback;
35 import org.eclipse.jetty.util.ConcurrentHashSet;
36
37 public class HttpConnectionOverHTTP2 extends HttpConnection
38 {
39 private final Set<HttpChannel> channels = new ConcurrentHashSet<>();
40 private final AtomicBoolean closed = new AtomicBoolean();
41 private final Session session;
42
43 public HttpConnectionOverHTTP2(HttpDestination destination, Session session)
44 {
45 super(destination);
46 this.session = session;
47 }
48
49 public Session getSession()
50 {
51 return session;
52 }
53
54 @Override
55 protected SendFailure send(HttpExchange exchange)
56 {
57 exchange.getRequest().version(HttpVersion.HTTP_2);
58 normalizeRequest(exchange.getRequest());
59
60
61 HttpChannel channel = newHttpChannel();
62 channels.add(channel);
63
64 return send(channel, exchange);
65 }
66
67 protected HttpChannelOverHTTP2 newHttpChannel()
68 {
69 return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession());
70 }
71
72 protected void release(HttpChannel channel)
73 {
74 channels.remove(channel);
75 getHttpDestination().release(this);
76 }
77
78 @Override
79 public boolean onIdleTimeout(long idleTimeout)
80 {
81 boolean close = super.onIdleTimeout(idleTimeout);
82 if (close)
83 close(new TimeoutException("idle_timeout"));
84 return false;
85 }
86
87 @Override
88 public void close()
89 {
90 close(new AsynchronousCloseException());
91 }
92
93 protected void close(Throwable failure)
94 {
95 if (closed.compareAndSet(false, true))
96 {
97 getHttpDestination().close(this);
98
99 abort(failure);
100
101 session.close(ErrorCode.NO_ERROR.code, failure.getMessage(), Callback.NOOP);
102 }
103 }
104
105 @Override
106 public boolean isClosed()
107 {
108 return closed.get();
109 }
110
111 private void abort(Throwable failure)
112 {
113 for (HttpChannel channel : channels)
114 {
115 HttpExchange exchange = channel.getHttpExchange();
116 if (exchange != null)
117 exchange.getRequest().abort(failure);
118 }
119 channels.clear();
120 }
121
122 @Override
123 public String toString()
124 {
125 return String.format("%s@%h[%s]",
126 getClass().getSimpleName(),
127 this,
128 session);
129 }
130 }