/* * Copyright (c) 2014 The APN-PROXY Project * * The APN-PROXY Project licenses this file to you 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 com.xx_dev.apn.proxy; import com.xx_dev.apn.proxy.utils.LoggerUtil; import io.netty.channel.*; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpResponse; import org.apache.log4j.Logger; /** * @author xmx * @version $Id: com.xx_dev.apn.proxy.ApnProxyRemoteForwardHandler 14-1-8 16:13 (xmx) Exp $ */ public class ApnProxyRemoteForwardHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger(ApnProxyRemoteForwardHandler.class); private static final Logger forwardRestLogger = Logger.getLogger("FORWARD_REST_LOGGER"); public static final String HANDLER_NAME = "apnproxy.remote.forward"; private Channel uaChannel; private RemoteChannelInactiveCallback remoteChannelInactiveCallback; private int remainMsgCount = 0; public ApnProxyRemoteForwardHandler(Channel uaChannel, RemoteChannelInactiveCallback remoteChannelInactiveCallback) { this.uaChannel = uaChannel; this.remoteChannelInactiveCallback = remoteChannelInactiveCallback; } @Override public void channelActive(ChannelHandlerContext remoteChannelCtx) throws Exception { LoggerUtil.debug(logger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), "Remote channel active"); remoteChannelCtx.read(); } public void channelRead(final ChannelHandlerContext remoteChannelCtx, final Object msg) throws Exception { LoggerUtil.debug(logger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), "Remote msg", msg); remainMsgCount++; if (remainMsgCount <= 5) { remoteChannelCtx.read(); } HttpObject ho = (HttpObject) msg; if (ho instanceof HttpResponse) { HttpResponse httpResponse = (HttpResponse) ho; LoggerUtil.info(forwardRestLogger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), httpResponse.getStatus(), httpResponse.getProtocolVersion()); httpResponse.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); httpResponse.headers().set("Proxy-Connection", HttpHeaders.Values.KEEP_ALIVE); } if (uaChannel.isActive()) { uaChannel.writeAndFlush(ho).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { LoggerUtil.debug(logger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), "Write to UA finished: " + future.isSuccess()); if (future.isSuccess()) { remainMsgCount--; remoteChannelCtx.read(); LoggerUtil.debug(logger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), "Fire read again"); } else { remoteChannelCtx.close(); } } }); } else { remoteChannelCtx.close(); } } @Override public void channelInactive(final ChannelHandlerContext remoteChannelCtx) throws Exception { LoggerUtil.debug(logger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), "Remote channel inactive"); final String remoteAddr = uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY).get().getRemote().getRemoteAddr(); remoteChannelInactiveCallback.remoteChannelInactive(uaChannel, remoteAddr); remoteChannelCtx.fireChannelInactive(); } @Override public void exceptionCaught(ChannelHandlerContext remoteChannelCtx, Throwable cause) throws Exception { logger.error(cause.getMessage() + uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), cause); remoteChannelCtx.close(); } public interface RemoteChannelInactiveCallback { public void remoteChannelInactive(Channel uaChannel, String remoeAddr) throws Exception; } }