com.xx_dev.apn.socks.local.FakeHttpClientDecoder.java Source code

Java tutorial

Introduction

Here is the source code for com.xx_dev.apn.socks.local.FakeHttpClientDecoder.java

Source

/*
 * 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.socks.local;

import com.xx_dev.apn.socks.common.utils.TextUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufProcessor;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.util.List;

public class FakeHttpClientDecoder extends ReplayingDecoder<FakeHttpClientDecoder.STATE> {

    private static final Logger logger = Logger.getLogger(FakeHttpClientDecoder.class);

    private static final Logger perfLogger = Logger.getLogger("PERF_LOGGER");

    private static final Logger trafficLogger = Logger.getLogger("TRAFFIC_LOGGER");

    enum STATE {
        READ_FAKE_HTTP, READ_CONTENT
    }

    private int length;

    public FakeHttpClientDecoder() {
        super(STATE.READ_FAKE_HTTP);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int startReaderIndex = in.readerIndex();

        long start = System.nanoTime();
        this._decode(ctx, in, out);
        long end = System.nanoTime();

        int endReaderIndex = in.readerIndex();

        perfLogger.debug("local decode: " + (endReaderIndex - startReaderIndex) + ", " + (end - start));

    }

    protected void _decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        switch (this.state()) {
        case READ_FAKE_HTTP: {
            int fakeHttpHeadStartIndex = in.readerIndex();

            int fakeHttpHeadEndIndex = in.forEachByte(new ByteBufProcessor() {
                int c = 0;

                @Override
                public boolean process(byte value) throws Exception {

                    if (value == '\r' || value == '\n') {
                        c++;
                    } else {
                        c = 0;
                    }

                    //logger.info("value=" + value + ", c=" + c);

                    if (c >= 4) {
                        return false;
                    } else {
                        return true;
                    }
                }
            });

            logger.debug("s: " + fakeHttpHeadStartIndex);
            logger.debug("e: " + fakeHttpHeadEndIndex);

            if (fakeHttpHeadEndIndex == -1) {
                logger.warn("w: " + fakeHttpHeadStartIndex);
                break;
            }

            byte[] buf = new byte[fakeHttpHeadEndIndex - fakeHttpHeadStartIndex + 1];
            in.readBytes(buf, 0, fakeHttpHeadEndIndex - fakeHttpHeadStartIndex + 1);
            String s = TextUtil.fromUTF8Bytes(buf);

            //logger.info(s);

            String[] ss = StringUtils.split(s, "\r\n");

            //System.out.println(s + "" + this + " " + Thread.currentThread().getName());

            for (String line : ss) {
                if (StringUtils.startsWith(line, "X-C:")) {
                    String lenStr = StringUtils.trim(StringUtils.split(line, ":")[1]);
                    //System.out.println(lenStr + "" + this + " " + Thread.currentThread().getName());
                    //System.out.println("*****************************************");
                    try {
                        length = Integer.parseInt(lenStr, 16);
                        trafficLogger.info("D," + LocalConfig.ins().getUser() + "," + length);
                    } catch (Throwable t) {
                        logger.error("--------------------------------------");
                        logger.error(s + "" + this + " " + Thread.currentThread().getName());
                        logger.error("--------------------------------------");
                    }

                }
            }

            this.checkpoint(STATE.READ_CONTENT);
        }
        case READ_CONTENT: {
            if (length > 0) {
                byte[] buf = new byte[length];
                in.readBytes(buf, 0, length);

                byte[] res = new byte[length];

                for (int i = 0; i < length; i++) {
                    res[i] = (byte) (buf[i] ^ (LocalConfig.ins().getEncryptKey() & 0xFF));
                }

                ByteBuf outBuf = ctx.alloc().buffer();

                outBuf.writeBytes(res);

                out.add(outBuf);
            }

            this.checkpoint(STATE.READ_FAKE_HTTP);
            break;
        }
        default:
            throw new Error("Shouldn't reach here.");
        }

    }

}