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.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          // One connection maps to N channels, so for each exchange we create a new channel.
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 }