/* * 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.masq; import cc.agentx.protocol.Http; import cc.agentx.util.KeyHelper; import java.security.SecureRandom; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class HttpFaker { private static final SecureRandom randomizer = new SecureRandom(); private static final DateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); private static final List<String> randomUrlList = new ArrayList<>(); // urls with no parameters private static final List<String> randomUrlList0 = new ArrayList<>(); // urls with parameters private static final Lock lock = new ReentrantLock(); private static final int randomUrlListSize = 100; private static final String[] entities = { "pub", "app", "articles", "question", "answer", "plugins", "account", "keywords", "blog", "en", "general", "doc", "game", "paper", "details", "index", "file", "resources", "book", "user", "map", "mail", "order", "people", "photo", "faq", "video", "support", "tools", "page", "news", "wiki", "html", "api", "package" }; private static final String[] operations = { "login", "signup", "register", "new", "index", "add", "remove", "update", "search", "scan", "register", "list", "like", "dislike", "q", "s", "submit", "download", "upload", "blob", "generate", "get", "delete", "confirm", "find" }; private static final String[] userAgents = { "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko", "Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko" }; private static final String[] domains = { "www.bing.com", "www.huawei.com", "www.mi.com", "www.apple.com", "www.amazon.com", "www.dell.com", "www.microsoft.com", "www.alibaba.com", "www.kfc.com", "www.yahoo.com", "www.163.com", "www.jd.com", "www.microsoft.com", "www.techcrunch.com", "www.zhihu.com", "user.bing.com", "product.huawei.com", "forum.mi.com", "help.apple.com", "buy.amazon.com", "translate.bing.com", "service.jd.com", "bill.taobao.com", "help.yahoo.com", "www.github.io" }; private static final String alphabeticString = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String alphanumericString = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; public static String pickup(String[] strings) { return strings[randomizer.nextInt(strings.length)]; } public static String randomAlphanumericString(int length) { StringBuilder buffer = new StringBuilder(); for (int i = 0; i < length; i++) { buffer.append(alphanumericString.charAt(randomizer.nextInt(62))); } return buffer.toString(); } public static String randomAlphabeticString(int length, boolean lowercase) { StringBuilder buffer = new StringBuilder(); if (lowercase) { for (int i = 0; i < length; i++) { buffer.append((char) (97 + randomizer.nextInt(26))); } } else { for (int i = 0; i < length; i++) { buffer.append(alphabeticString.charAt(randomizer.nextInt(52))); } } return buffer.toString(); } public static String getRandomUrl(boolean withParameters) { return "http://".concat(pickup(domains)).concat(getRandomUri(withParameters)); } public static String getRandomUri(boolean withParameters) { synchronized (lock) { if (!withParameters) { if (randomUrlList.size() == 0) { for (int i = 0; i < randomUrlListSize; i++) { randomUrlList.add(randomUri(false)); } } return randomUrlList.remove(randomUrlList.size() - 1); } else { if (randomUrlList0.size() == 0) { for (int i = 0; i < randomUrlListSize; i++) { randomUrlList0.add(randomUri(true)); } } return randomUrlList0.remove(randomUrlList0.size() - 1); } } } public static String getRandomUserAgent() { return pickup(userAgents); } public static String getRandomRequestHeader(String method, boolean placeholder) { StringBuilder buffer = new StringBuilder(); switch (method) { case Http.METHOD_GET: buffer.append("GET ").append(getRandomUri(randomizer.nextBoolean())); buffer.append(" ").append(Http.VERSION_1_1).append(Http.CRLF); buffer.append("Host: ").append(pickup(domains)).append(Http.CRLF); buffer.append("Connection: keep-alive").append(Http.CRLF); if (randomizer.nextBoolean()) buffer.append("Cache-Control: max-age=0").append(Http.CRLF); if (randomizer.nextBoolean()) buffer.append("Accept: ").append("*/*").append(Http.CRLF); buffer.append("DNT: 1").append(Http.CRLF); buffer.append("User-Agent: ").append(getRandomUserAgent()).append(Http.CRLF); buffer.append("Accept-Encoding: gzip, deflate").append(Http.CRLF); buffer.append("Accept-Language: zh-CN,zh;q=0.").append(randomizer.nextInt(9) + 1).append(Http.CRLF); if (placeholder) { buffer.append("Cookie: "); for (int i = 0; i < randomizer.nextInt(2); i++) buffer.append(randomAlphabeticString(randomizer.nextInt(3) + 1, true)).append("=").append(randomAlphanumericString(randomizer.nextInt(16) + 1)).append("; "); buffer.append(randomAlphabeticString(randomizer.nextInt(3) + 1, true)).append("_").append(randomAlphabeticString(randomizer.nextInt(3) + 1, true)).append("=").append("$").append("; "); for (int i = 0; i < randomizer.nextInt(2); i++) buffer.append(randomAlphabeticString(randomizer.nextInt(3) + 1, true)).append("=").append(randomAlphanumericString(randomizer.nextInt(16) + 1)).append("; "); buffer.append(randomAlphabeticString(randomizer.nextInt(3) + 1, true)).append("=").append(randomAlphanumericString(randomizer.nextInt(16) + 1)).append(Http.CRLF); } buffer.append(Http.CRLF); break; case Http.METHOD_POST: String host = pickup(domains); buffer.append("POST ").append(getRandomUri(false)).append(" ").append(Http.VERSION_1_1).append(Http.CRLF); buffer.append("Host: ").append(host).append(Http.CRLF); buffer.append("Connection: keep-alive").append(Http.CRLF); buffer.append("Content-Length: ").append(placeholder ? "$" : "0").append(Http.CRLF); buffer.append("Accept: ").append("*/*").append(Http.CRLF); if (randomizer.nextInt(10) < 3) buffer.append("Origin: http://").append(host).append(Http.CRLF); else if (randomizer.nextInt(10) < 7) { buffer.append("Referer: ").append("http://").append(host).append(randomUri(false)).append(Http.CRLF); } buffer.append("User-Agent: ").append(getRandomUserAgent()).append(Http.CRLF); buffer.append("Content-Type: application/octet-stream").append(Http.CRLF); buffer.append("DNT: 1").append(Http.CRLF); buffer.append("Accept-Encoding: gzip, deflate").append(Http.CRLF); buffer.append("Accept-Language: zh-CN,zh;q=0.").append(randomizer.nextInt(9) + 1).append(Http.CRLF); buffer.append(Http.CRLF); break; default: throw new RuntimeException("method not support: " + method); } return buffer.toString(); } public static String getRandomResponseHeader(String response, boolean placeholder) { if (!response.equals(Http.RESPONSE_200)) { throw new RuntimeException("response not support"); } StringBuilder buffer = new StringBuilder(); buffer.append(Http.VERSION_1_1).append(" ").append(response).append(Http.CRLF); switch (randomizer.nextInt(10)) { case 0: buffer.append("Server: nginx").append(Http.CRLF); break; case 1: buffer.append("Server: AmazonS3").append(Http.CRLF); break; case 2: buffer.append("Server: Tengine").append(Http.CRLF); break; case 3: buffer.append("Server: Apache").append(Http.CRLF); break; case 4: buffer.append("Server: cafe").append(Http.CRLF); break; } buffer.append("Connection: keep-alive").append(Http.CRLF); buffer.append("Content-Type: ").append(randomizer.nextBoolean() ? "application/octet-stream" : "gzip").append(Http.CRLF); buffer.append("Content-Length: ").append(placeholder ? "$" : randomizer.nextInt(8192) + 1).append(Http.CRLF); String time = dateFormat.format(new Date()); buffer.append("Date: ").append(time).append(Http.CRLF); buffer.append("Last-Modified: ").append(time).append(Http.CRLF); buffer.append(Http.CRLF); return buffer.toString(); } public static String randomUri(boolean withParameters) { StringBuilder buffer = new StringBuilder(); buffer.append("/").append(pickup(entities)).append("/"); if (randomizer.nextBoolean()) { if (randomizer.nextBoolean()) buffer.append(KeyHelper.generateRandomInteger(2000, 2017)).append("/") .append(KeyHelper.generateRandomInteger(1, 13)).append("/") .append(KeyHelper.generateRandomInteger(1, 32)).append("/"); if (randomizer.nextBoolean()) buffer.append(randomizer.nextInt(65536)).append("/"); else buffer.append(randomAlphanumericString(randomizer.nextInt(16) + 1)) .append(randomizer.nextBoolean() ? ".html" : "/"); } else { buffer.append(randomizer.nextBoolean() ? pickup(operations) : randomAlphabeticString(randomizer.nextInt(5) + 1, true)).append(".html"); } if (withParameters) { buffer.append("?"); for (int i = 0; i < randomizer.nextInt(3) + 1; i++) { if (i > 0) buffer.append("&"); buffer.append(randomAlphabeticString(randomizer.nextInt(3) + 1, true)).append("=") .append(randomizer.nextBoolean() ? randomizer.nextInt(65536) : randomAlphanumericString(randomizer.nextInt(32))); } } return buffer.toString(); } }