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
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 }