cc.agentx.wrapper.FakedHttpWrapper.java Source code

Java tutorial

Introduction

Here is the source code for cc.agentx.wrapper.FakedHttpWrapper.java

Source

/*
 * Copyright 2017 ZhangJiupeng
 *
 * Licensed 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 cc.agentx.wrapper;

import cc.agentx.masq.HttpFaker;
import cc.agentx.protocol.Http;
import cc.agentx.util.KeyHelper;
import org.bouncycastle.util.Arrays;

import java.util.Base64;
import java.util.regex.Matcher;

public class FakedHttpWrapper extends Wrapper {
    private boolean requestMode;
    private Base64.Encoder encoder;
    private Base64.Decoder decoder;

    public FakedHttpWrapper(boolean requestMode) {
        this.requestMode = requestMode;
        this.encoder = Base64.getUrlEncoder();
        this.decoder = Base64.getUrlDecoder();
    }

    @Override
    public byte[] wrap(final byte[] bytes) {
        if (requestMode) {
            return warpInRequest(bytes);
        } else {
            return wrapInResponse(bytes);
        }
    }

    private byte[] warpInRequest(final byte[] bytes) {
        String encodedStr = encoder.encodeToString(bytes).replaceAll("=", "");

        // 20 percent of small data are faked by post method requests
        if (bytes.length > 512 || KeyHelper.generateRandomInteger(0, 10) < 2) {
            String header = HttpFaker.getRandomRequestHeader(Http.METHOD_POST, true);
            header = header.replaceAll(Matcher.quoteReplacement("$"), String.valueOf(encodedStr.length()));
            return Arrays.concatenate(header.getBytes(), encodedStr.getBytes());
        } else {
            String header = HttpFaker.getRandomRequestHeader(Http.METHOD_GET, true);
            header = header.replaceAll(Matcher.quoteReplacement("$"), encodedStr);
            return header.getBytes();
        }
    }

    private byte[] wrapInResponse(final byte[] bytes) {
        String header = HttpFaker.getRandomResponseHeader(Http.RESPONSE_200, true);
        header = header.replaceAll(Matcher.quoteReplacement("$"), String.valueOf(bytes.length));
        return Arrays.concatenate(header.getBytes(), bytes);
    }

    @Override
    public byte[] unwrap(final byte[] bytes) {
        if (requestMode) {
            return unwrapFromRequest(bytes);
        } else {
            return unwrapFromResponse(bytes);
        }
    }

    private byte[] unwrapFromRequest(final byte[] bytes) {
        String decodedStr = new String(bytes);
        String rawStr = null;
        if (decodedStr.startsWith(Http.METHOD_GET)) {
            for (String line : decodedStr.split(Http.CRLF)) {
                if (line.startsWith("Cookie: ")) {
                    for (String cookie : line.substring(5).split("; ")) {
                        String[] kvPair = cookie.split("=");
                        if (kvPair.length == 2 && kvPair[0].contains("_")) {
                            rawStr = kvPair[1];
                            break;
                        }
                    }
                    break;
                }
            }
            if (rawStr == null) {
                return new byte[0];
            }
        } else if (decodedStr.startsWith(Http.METHOD_POST)) {
            String[] parts = decodedStr.split(Http.CRLF.concat(Http.CRLF));
            if (parts.length != 2) {
                return new byte[0];
            }
            rawStr = parts[1];
        } else {
            throw new RuntimeException("unknown format");
        }
        StringBuilder buffer = new StringBuilder(rawStr);
        while (buffer.length() % 4 != 0)
            buffer.append('=');
        return decoder.decode(buffer.toString());
    }

    public byte[] unwrapFromResponse(final byte[] bytes) {
        // caution: placeholder bytes' end-pos must less than 200
        String fuzzyHeader = new String(Arrays.copyOfRange(bytes, 0, 200));
        if (!fuzzyHeader.startsWith(Http.VERSION_1_1)) {
            throw new RuntimeException("unknown format");
        }
        fuzzyHeader = fuzzyHeader.substring(fuzzyHeader.indexOf("Content-Length: ") + "Content-Length: ".length());
        fuzzyHeader = fuzzyHeader.substring(0, fuzzyHeader.indexOf(Http.CRLF));
        int rawLen = Integer.parseInt(fuzzyHeader);
        return Arrays.copyOfRange(bytes, bytes.length - rawLen, bytes.length);
    }

}