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  
24  import org.eclipse.jetty.client.HttpChannel;
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.SendFailure;
29  import org.eclipse.jetty.http.HttpVersion;
30  import org.eclipse.jetty.http2.ErrorCode;
31  import org.eclipse.jetty.http2.api.Session;
32  import org.eclipse.jetty.util.Callback;
33  import org.eclipse.jetty.util.ConcurrentHashSet;
34  
35  public class HttpConnectionOverHTTP2 extends HttpConnection
36  {
37      private final Set<HttpChannel> channels = new ConcurrentHashSet<>();
38      private final Session session;
39  
40      public HttpConnectionOverHTTP2(HttpDestination destination, Session session)
41      {
42          super(destination);
43          this.session = session;
44      }
45  
46      public Session getSession()
47      {
48          return session;
49      }
50  
51      @Override
52      protected SendFailure send(HttpExchange exchange)
53      {
54          exchange.getRequest().version(HttpVersion.HTTP_2);
55          normalizeRequest(exchange.getRequest());
56  
57          // One connection maps to N channels, so for each exchange we create a new channel.
58          HttpChannel channel = newHttpChannel();
59          channels.add(channel);
60  
61          return send(channel, exchange);
62      }
63  
64      protected HttpChannelOverHTTP2 newHttpChannel()
65      {
66          return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession());
67      }
68  
69      protected void release(HttpChannel channel)
70      {
71          channels.remove(channel);
72          getHttpDestination().release(this);
73      }
74  
75      @Override
76      public void close()
77      {
78          close(new AsynchronousCloseException());
79      }
80  
81      protected void close(Throwable failure)
82      {
83          // First close then abort, to be sure that the connection cannot be reused
84          // from an onFailure() handler or by blocking code waiting for completion.
85          getHttpDestination().close(this);
86          session.close(ErrorCode.NO_ERROR.code, failure.getMessage(), Callback.NOOP);
87          abort(failure);
88      }
89  
90      private void abort(Throwable failure)
91      {
92          for (HttpChannel channel : channels)
93          {
94              HttpExchange exchange = channel.getHttpExchange();
95              if (exchange != null)
96                  exchange.getRequest().abort(failure);
97          }
98          channels.clear();
99      }
100 
101     @Override
102     public String toString()
103     {
104         return String.format("%s@%h[%s]",
105                 getClass().getSimpleName(),
106                 this,
107                 session);
108     }
109 }