View Javadoc
1   package org.littleshoot.proxy;
2   
3   import org.jboss.netty.buffer.ChannelBuffer;
4   import org.jboss.netty.channel.Channel;
5   import org.jboss.netty.channel.ChannelFuture;
6   import org.jboss.netty.channel.ChannelFutureListener;
7   import org.jboss.netty.channel.ChannelHandlerContext;
8   import org.jboss.netty.channel.ChannelStateEvent;
9   import org.jboss.netty.channel.ExceptionEvent;
10  import org.jboss.netty.channel.MessageEvent;
11  import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
12  import org.jboss.netty.channel.ChannelHandler.Sharable;
13  import org.jboss.netty.channel.group.ChannelGroup;
14  import org.slf4j.Logger;
15  import org.slf4j.LoggerFactory;
16  
17  /***
18   * Class that simply relays traffic the channel this is connected to to 
19   * another channel passed in to the constructor.
20   */
21  @Sharable
22  public class HttpConnectRelayingHandler extends SimpleChannelUpstreamHandler {
23      
24      private static final Logger LOG = 
25          LoggerFactory.getLogger(HttpConnectRelayingHandler.class);
26      
27      /***
28       * The channel to relay to. This could be a connection from the browser
29       * to the proxy or it could be a connection from the proxy to an external
30       * site.
31       */
32      private final Channel relayChannel;
33  
34      private final ChannelGroup channelGroup;
35  
36      /***
37       * Creates a new {@link HttpConnectRelayingHandler} with the specified 
38       * connection to relay to..
39       * 
40       * @param relayChannel The channel to relay messages to.
41       * @param channelGroup The group of channels to close on shutdown.
42       */
43      public HttpConnectRelayingHandler(final Channel relayChannel, 
44          final ChannelGroup channelGroup) {
45          this.relayChannel = relayChannel;
46          this.channelGroup = channelGroup;
47      }
48  
49      @Override
50      public void messageReceived(final ChannelHandlerContext ctx, 
51          final MessageEvent e) throws Exception {
52          final ChannelBuffer msg = (ChannelBuffer) e.getMessage();
53          if (relayChannel.isConnected()) {
54              final ChannelFutureListener logListener = 
55                  new ChannelFutureListener() {
56                  public void operationComplete(final ChannelFuture future) 
57                      throws Exception {
58                      LOG.debug("Finished writing data on CONNECT channel");
59                  }
60              };
61              relayChannel.write(msg).addListener(logListener);
62          }
63          else {
64              LOG.info("Channel not open. Connected? {}", 
65                  relayChannel.isConnected());
66              // This will undoubtedly happen anyway, but just in case.
67              ProxyUtils.closeOnFlush(e.getChannel());
68          }
69      }
70      
71      @Override
72      public void channelOpen(final ChannelHandlerContext ctx, 
73          final ChannelStateEvent cse) throws Exception {
74          final Channel ch = cse.getChannel();
75          LOG.info("New CONNECT channel opened from proxy to web: {}", ch);
76          if (this.channelGroup != null) {
77              this.channelGroup.add(ch);
78          }
79      }
80  
81      @Override
82      public void channelClosed(final ChannelHandlerContext ctx, 
83          final ChannelStateEvent e) throws Exception {
84          LOG.info("Got closed event on proxy -> web connection: {}", 
85              e.getChannel());
86          ProxyUtils.closeOnFlush(this.relayChannel);
87      }
88  
89      @Override
90      public void exceptionCaught(final ChannelHandlerContext ctx, 
91          final ExceptionEvent e) throws Exception {
92          LOG.warn("Caught exception on proxy -> web connection: "+
93              e.getChannel(), e.getCause());
94          ProxyUtils.closeOnFlush(e.getChannel());
95      }
96  }