Package org.snova.framework.proxy.c4

Source Code of org.snova.framework.proxy.c4.C4RemoteHandler

/**
*
*/
package org.snova.framework.proxy.c4;

import java.util.List;
import java.util.Map;

import org.arch.buffer.Buffer;
import org.arch.common.KeyValuePair;
import org.arch.config.IniProperties;
import org.arch.event.Event;
import org.arch.event.EventHandler;
import org.arch.event.EventHeader;
import org.arch.event.http.HTTPEventContants;
import org.arch.event.http.HTTPRequestEvent;
import org.arch.event.http.HTTPResponseEvent;
import org.arch.util.StringHelper;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.handler.codec.http.DefaultHttpChunk;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpChunk;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.HttpVersion;
import org.jboss.netty.util.internal.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snova.framework.common.http.SetCookieHeaderValue;
import org.snova.framework.config.SnovaConfiguration;
import org.snova.framework.event.CommonEventConstants;
import org.snova.framework.event.SocketConnectionEvent;
import org.snova.framework.event.TCPChunkEvent;
import org.snova.framework.proxy.LocalProxyHandler;
import org.snova.framework.proxy.RemoteProxyHandler;
import org.snova.framework.proxy.c4.http.HttpTunnelService;
import org.snova.framework.proxy.c4.ws.WSTunnelService;
import org.snova.framework.proxy.gae.GAEConfig;
import org.snova.framework.proxy.range.MultiRangeFetchTask;
import org.snova.framework.proxy.range.RangeCallback;
import org.snova.framework.server.ProxyHandler;
import org.snova.http.client.HttpClientHelper;
import org.snova.http.client.common.SimpleSocketAddress;

/**
* @author yinqiwen
*
*/
public class C4RemoteHandler implements RemoteProxyHandler, EventHandler,
        RangeCallback
{
  protected static Logger                       logger           = LoggerFactory
                                                                       .getLogger(C4RemoteHandler.class);
  private static Map<Integer, C4RemoteHandler>  sessionTable  = new ConcurrentHashMap<Integer, C4RemoteHandler>();
 
  private C4ServerAuth                       server;
  private LocalProxyHandler                   localHandler;
  private int                                   sequence       = 0;
 
  private HttpTunnelService                   http;
  private WSTunnelService                       ws;
  private SimpleSocketAddress                   proxyAddr;
  private MultiRangeFetchTask                   rangeTask       = null;
  private boolean                               isClosed;
  boolean                                       injectRange   = false;
 
  public static C4RemoteHandler getSession(int sid)
  {
    return sessionTable.get(sid);
  }
 
  public C4RemoteHandler(C4ServerAuth s)
  {
    this.server = s;
    if (isWebsocketServer())
    {
      ws = WSTunnelService.getWSTunnelService(s);
    }
    else
    {
      http = HttpTunnelService.getHttpTunnelService(s);
    }
   
  }
 
  private boolean isWebsocketServer()
  {
    return (server.url.getScheme().equalsIgnoreCase("ws") || server.url
            .getScheme().equalsIgnoreCase("wss"));
  }
 
  private HTTPRequestEvent buildHttpRequestEvent(HttpRequest request)
  {
    HTTPRequestEvent event = new HTTPRequestEvent();
    event.method = request.getMethod().getName();
    event.url = request.getUri();
    if (event.url.startsWith("http://"))
    {
      int idx = event.url.indexOf('/', 7);
      if (idx == -1)
      {
        event.url = "/";
      }
      else
      {
        event.url = event.url.substring(idx);
      }
    }
    event.version = request.getProtocolVersion().getText();
    event.setHash(localHandler.getId());
    event.setAttachment(request);
    String host = HttpHeaders.getHost(request);
    if (null == host)
    {
      logger.error(String.format("Session[%d] invalid request.",
              localHandler.getId(), request));
      return null;
    }
    proxyAddr = HttpClientHelper.getHttpRemoteAddress(request.getMethod()
            .equals(HttpMethod.CONNECT), HttpHeaders.getHost(request));
    ChannelBuffer content = request.getContent();
    if (null != content)
    {
      content.markReaderIndex();
      int buflen = content.readableBytes();
      event.content.ensureWritableBytes(content.readableBytes());
      content.readBytes(event.content.getRawBuffer(),
              event.content.getWriteIndex(), content.readableBytes());
      event.content.advanceWriteIndex(buflen);
    }
    for (String name : request.getHeaderNames())
    {
      for (String value : request.getHeaders(name))
      {
        event.headers
                .add(new KeyValuePair<String, String>(name, value));
      }
    }
    return event;
  }
 
  @Override
  public void handleRequest(LocalProxyHandler local, HttpRequest req)
  {
    localHandler = local;
    sessionTable.put(local.getId(), this);
    logger.info(String.format("Session[%d]Request %s %s",
            localHandler.getId(), req.getMethod(), req.getUri()));
    Event ev = buildHttpRequestEvent(req);
    if (null == ev)
    {
      local.close();
      return;
    }
    if (req.getMethod().equals(HttpMethod.CONNECT))
    {
      ChannelPipeline pipeline = local.getLocalChannel().getPipeline();
      ProxyHandler p = (ProxyHandler) pipeline.get("handler");
      p.switchRawHandler();
    }
    else
    {
      if (req.getMethod().equals(HttpMethod.GET))
      {
        IniProperties cfg = SnovaConfiguration.getInstance()
                .getIniProperties();
        if (cfg.getIntProperty("C4", "MultiRangeFetchEnable", 0) == 1)
        {
          if (StringHelper.containsString(HttpHeaders.getHost(req),
                  C4Config.injectRange) || injectRange)
          {
           
            rangeTask = new MultiRangeFetchTask();
            rangeTask.sessionID = local.getId();
            rangeTask.fetchLimit = cfg.getIntProperty("GAE",
                    "RangeFetchLimitSize", 256 * 1024);
            rangeTask.fetchWorkerNum = cfg.getIntProperty("GAE",
                    "RangeConcurrentFetcher", 3);
            rangeTask.asyncGet((HTTPRequestEvent) ev, this);
            return;
          }
        }
      }
    }
    requestEvent(ev);
  }
 
  void requestEvent(Event ev)
  {
    if (isWebsocketServer())
    {
      if (null != ws)
      {
        ws.write(ev);
      }
    }
    else
    {
      if (null != http)
      {
        http.write(ev);
      }
    }
  }
 
  @Override
  public void handleChunk(LocalProxyHandler local, HttpChunk chunk)
  {
    handleRawData(local, chunk.getContent());
  }
 
  @Override
  public void handleRawData(LocalProxyHandler local, ChannelBuffer raw)
  {
    TCPChunkEvent ev = new TCPChunkEvent();
    ev.setHash(local.getId());
    ev.sequence = this.sequence++;
    ChannelBuffer buf = raw;
    ev.content = new byte[buf.readableBytes()];
    buf.readBytes(ev.content);
    requestEvent(ev);
  }
 
  @Override
  public void close()
  {
    if (!isClosed)
    {
      logger.info(String.format("Session[%d]closed", localHandler.getId()));
      SocketConnectionEvent closeEv = new SocketConnectionEvent();
      closeEv.status = SocketConnectionEvent.TCP_CONN_CLOSED;
      closeEv.addr = proxyAddr.toString();
      closeEv.setHash(localHandler.getId());
      requestEvent(closeEv);
      int sid = null != localHandler ? localHandler.getId() : 0;
      sessionTable.remove(sid);
    }
    if (null != rangeTask)
    {
      rangeTask.close();
    }
  }
 
  @Override
  public void onEvent(EventHeader header, Event event)
  {
    switch (header.type)
    {
      case HTTPEventContants.HTTP_RESPONSE_EVENT_TYPE:
      {
        logger.info(String.format(
                "Session[%d]Handle HTTP response event.",
                localHandler.getId()));
        HTTPResponseEvent res = (HTTPResponseEvent) event;
        if (null != rangeTask)
        {
          if (!rangeTask.processAsyncResponse(res))
          {
            close();
          }
        }
        else
        {
         
        }
        break;
      }
      case CommonEventConstants.EVENT_TCP_CHUNK_TYPE:
      {
        TCPChunkEvent chunk = (TCPChunkEvent) event;
        localHandler.handleRawData(this,
                ChannelBuffers.wrappedBuffer(chunk.content));
        logger.info(String.format("Session[%d]Handle TCP chunk %d:%d",
                localHandler.getId(), chunk.sequence,
                chunk.content.length));
        break;
      }
      case CommonEventConstants.EVENT_TCP_CONNECTION_TYPE:
      {
        SocketConnectionEvent ev = (SocketConnectionEvent) event;
        if (ev.status == SocketConnectionEvent.TCP_CONN_CLOSED)
        {
         
          if (null != proxyAddr
                  && proxyAddr.toString().equals(ev.addr))
          {
            close();
            localHandler.close();
          }
        }
        break;
      }
    }
  }
 
  @Override
  public String getName()
  {
    return "C4";
  }
 
  private HttpResponse buildHttpResponse(HTTPResponseEvent ev)
  {
    int status = ev.statusCode;
    HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
            HttpResponseStatus.valueOf(status));
   
    List<KeyValuePair<String, String>> headers = ev.getHeaders();
    for (KeyValuePair<String, String> header : headers)
    {
      response.addHeader(header.getName(), header.getValue());
    }
   
    if (null == response.getHeader(HttpHeaders.Names.CONTENT_LENGTH))
    {
      response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, ""
              + ev.content.readableBytes());
    }
   
    response.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
    if (HttpHeaders.getContentLength(response) == ev.content
            .readableBytes())
    {
      ChannelBuffer bufer = ChannelBuffers.wrappedBuffer(
              ev.content.getRawBuffer(), ev.content.getReadIndex(),
              ev.content.readableBytes());
      response.setContent(bufer);
    }
    else
    {
      response.setChunked(true);
      // response.setTransferEncoding(HttpTransferEncoding.STREAMED);
    }
    return response;
  }
 
  @Override
  public void onHttpResponse(HTTPResponseEvent res)
  {
    if (null != localHandler)
    {
      HttpResponse httpres = buildHttpResponse(res);
      localHandler.handleResponse(this, httpres);
      if (httpres.isChunked())
      {
        Buffer content = res.content;
        HttpChunk chunk = new DefaultHttpChunk(
                ChannelBuffers.wrappedBuffer(content.getRawBuffer(),
                        content.getReadIndex(), content.readableBytes()));
        localHandler.handleChunk(this, chunk);
      }
    }
    else
    {
      close();
    }
  }
 
  @Override
  public void onRangeChunk(Buffer buf)
  {
    if (null != localHandler)
    {
      HttpChunk chunk = new DefaultHttpChunk(
              ChannelBuffers.wrappedBuffer(buf.getRawBuffer(),
                      buf.getReadIndex(), buf.readableBytes()));
      localHandler.handleChunk(this, chunk);
    }
    else
    {
      close();
    }
  }
 
  @Override
  public void writeHttpReq(HTTPRequestEvent req)
  {
    if (req.url.startsWith("http://"))
    {
      int idx = req.url.indexOf('/', 7);
      if (idx == -1)
      {
        req.url = "/";
      }
      else
      {
        req.url = req.url.substring(idx);
      }
    }
    requestEvent(req);
  }
}
TOP

Related Classes of org.snova.framework.proxy.c4.C4RemoteHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.