/* * Copyright (c) 2013-2014 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.werval.server.netty; import io.werval.spi.ApplicationSPI; import io.werval.spi.dev.DevShellSPI; import io.werval.spi.server.HttpServerHelper; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static io.werval.runtime.ConfigKeys.WERVAL_HTTP_REQUESTS_BODY_DISK_THRESHOLD; import static io.werval.runtime.ConfigKeys.WERVAL_HTTP_REQUESTS_BODY_MAX_SIZE; /** * Distinguish HttpRequests and WebSocketFrames and setup the pipeline accordingly. */ public class SubProtocolSwitchHandler extends SimpleChannelInboundHandler<Object> { private static final Logger LOG = LoggerFactory.getLogger( SubProtocolSwitchHandler.class ); private final ChannelGroup allChannels; private final ApplicationSPI app; private final DevShellSPI devSpi; private final HttpServerHelper helper = new HttpServerHelper(); public SubProtocolSwitchHandler( ChannelGroup allChannels, ApplicationSPI app, DevShellSPI devSpi ) { super(); this.allChannels = allChannels; this.app = app; this.devSpi = devSpi; } @Override public void channelActive( ChannelHandlerContext context ) { allChannels.add( context.channel() ); } @Override protected void channelRead0( ChannelHandlerContext context, Object message ) throws Exception { if( message instanceof HttpRequest ) { HttpRequest request = (HttpRequest) message; LOG.trace( "Switching to plain HTTP protocol" ); ChannelPipeline pipeline = context.pipeline(); long maxBodySize = app.config().longNumber( WERVAL_HTTP_REQUESTS_BODY_MAX_SIZE ); long diskThreshold = app.config().longNumber( WERVAL_HTTP_REQUESTS_BODY_DISK_THRESHOLD ); pipeline.addLast( "http-aggregator", new HttpRequestAggregator( helper, app.events(), maxBodySize, diskThreshold, app.tmpdir() ) ); pipeline.addLast( "werval-http", new WervalHttpHandler( app, devSpi ) ); pipeline.remove( this ); context.fireChannelRead( request ); } else if( message instanceof WebSocketFrame ) { WebSocketFrame frame = (WebSocketFrame) message; LOG.trace( "Switching to WebSocket protocol" ); ChannelPipeline pipeline = context.pipeline(); pipeline.addLast( "werval-websocket", new WervalSocketHandler( app, devSpi ) ); pipeline.remove( this ); frame.retain(); // TODO Check this context.fireChannelRead( frame ); } else { LOG.warn( "Received a message of an unknown type ({}), channel will be closed.", message.getClass() ); context.channel().close(); } } }