View Javadoc

1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.codec.spdy;
17  
18  import javax.net.ssl.SSLEngine;
19  
20  import org.jboss.netty.channel.ChannelEvent;
21  import org.jboss.netty.channel.ChannelHandler;
22  import org.jboss.netty.channel.ChannelHandlerContext;
23  import org.jboss.netty.channel.ChannelPipeline;
24  import org.jboss.netty.channel.ChannelUpstreamHandler;
25  import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
26  import org.jboss.netty.handler.codec.http.HttpRequest;
27  import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
28  import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
29  import org.jboss.netty.handler.ssl.SslHandler;
30  
31  /**
32   * {@link ChannelUpstreamHandler} which is responsible to setup the {@link ChannelPipeline} either for
33   * HTTP or SPDY. This offers an easy way for users to support both at the same time while not care to
34   * much about the low-level details.
35   *
36   */
37  public abstract class SpdyOrHttpChooser implements ChannelUpstreamHandler {
38  
39      public enum SelectedProtocol {
40          SpdyVersion2,
41          SpdyVersion3,
42          HttpVersion1_1,
43          HttpVersion1_0,
44          None
45      }
46  
47      private final int maxSpdyContentLength;
48      private final int maxHttpContentLength;
49  
50      protected SpdyOrHttpChooser(int maxSpdyContentLength, int maxHttpContentLength) {
51          this.maxSpdyContentLength = maxSpdyContentLength;
52          this.maxHttpContentLength = maxHttpContentLength;
53      }
54  
55      /**
56       * Return the {@link SelectedProtocol} for the {@link SSLEngine}. If its not known yet implementations
57       * MUST return {@link SelectedProtocol#None}.
58       *
59       */
60      protected abstract SelectedProtocol getProtocol(SSLEngine engine);
61  
62      public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
63          // Get the SslHandler from the ChannelPipeline so we can obtain the SslEngine from it.
64          SslHandler handler = ctx.getPipeline().get(SslHandler.class);
65          if (handler == null) {
66              // SslHandler is needed by SPDY by design.
67              throw new IllegalStateException("SslHandler is needed for SPDY");
68          }
69  
70          ChannelPipeline pipeline = ctx.getPipeline();
71          SelectedProtocol protocol = getProtocol(handler.getEngine());
72          switch (protocol) {
73          case None:
74              // Not done with choosing the protocol, so just return here for now,
75              return;
76          case SpdyVersion2:
77              addSpdyHandlers(ctx, 2);
78              break;
79          case SpdyVersion3:
80              addSpdyHandlers(ctx, 3);
81              break;
82          case HttpVersion1_0:
83          case HttpVersion1_1:
84              addHttpHandlers(ctx);
85              break;
86          default:
87              throw new IllegalStateException("Unknown SelectedProtocol");
88          }
89          // When we reached here we can remove this handler as its now clear what protocol we want to use
90          // from this point on.
91          pipeline.remove(this);
92          ctx.sendUpstream(e);
93      }
94  
95      /**
96       * Add all {@link ChannelHandler}'s that are needed for SPDY with the given version.
97       */
98      protected void addSpdyHandlers(ChannelHandlerContext ctx, int version) {
99          ChannelPipeline pipeline = ctx.getPipeline();
100         pipeline.addLast("spdyDecoder", new SpdyFrameDecoder(version));
101         pipeline.addLast("spdyEncoder", new SpdyFrameEncoder(version));
102         pipeline.addLast("spdySessionHandler", new SpdySessionHandler(version, true));
103         pipeline.addLast("spdyHttpEncoder", new SpdyHttpEncoder(version));
104         pipeline.addLast("spdyHttpDecoder", new SpdyHttpDecoder(version, maxSpdyContentLength));
105         pipeline.addLast("spdyStreamIdHandler", new SpdyHttpResponseStreamIdHandler());
106         pipeline.addLast("httpRquestHandler", createHttpRequestHandlerForSpdy());
107     }
108 
109     /**
110      * Add all {@link ChannelHandler}'s that are needed for HTTP.
111      */
112     protected void addHttpHandlers(ChannelHandlerContext ctx) {
113         ChannelPipeline pipeline = ctx.getPipeline();
114         pipeline.addLast("httpRquestDecoder", new HttpRequestDecoder());
115         pipeline.addLast("httpResponseEncoder", new HttpResponseEncoder());
116         pipeline.addLast("httpChunkAggregator", new HttpChunkAggregator(maxHttpContentLength));
117         pipeline.addLast("httpRquestHandler", createHttpRequestHandlerForHttp());
118     }
119 
120     /**
121      * Create the {@link ChannelUpstreamHandler} that is responsible for handling the {@link HttpRequest}'s
122      * when the {@link SelectedProtocol} was {@link SelectedProtocol#HttpVersion1_0} or
123      * {@link SelectedProtocol#HttpVersion1_1}
124      */
125     protected abstract ChannelUpstreamHandler createHttpRequestHandlerForHttp();
126 
127     /**
128      * Create the {@link ChannelUpstreamHandler} that is responsible for handling the {@link HttpRequest}'s
129      * when the {@link SelectedProtocol} was {@link SelectedProtocol#SpdyVersion2} or
130      * {@link SelectedProtocol#SpdyVersion3}.
131      *
132      * Bye default this method will just delecate to {@link #createHttpRequestHandlerForHttp()}, but
133      * sub-classes may override this to change the behaviour.
134      */
135     protected ChannelUpstreamHandler createHttpRequestHandlerForSpdy() {
136         return createHttpRequestHandlerForHttp();
137     }
138 }