001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.benchmark; 028 029import java.io.File; 030import java.net.URL; 031import java.security.cert.CertificateException; 032import java.security.cert.X509Certificate; 033import java.util.concurrent.LinkedBlockingQueue; 034import java.util.concurrent.ThreadFactory; 035import java.util.concurrent.ThreadPoolExecutor; 036import java.util.concurrent.TimeUnit; 037 038import javax.net.SocketFactory; 039import javax.net.ssl.SSLContext; 040 041import org.apache.commons.cli.CommandLine; 042import org.apache.commons.cli.CommandLineParser; 043import org.apache.commons.cli.Options; 044import org.apache.commons.cli.PosixParser; 045import org.apache.http.Header; 046import org.apache.http.HttpEntity; 047import org.apache.http.HttpHost; 048import org.apache.http.HttpRequest; 049import org.apache.http.HttpVersion; 050import org.apache.http.entity.ContentType; 051import org.apache.http.entity.FileEntity; 052import org.apache.http.entity.StringEntity; 053import org.apache.http.message.BasicHttpEntityEnclosingRequest; 054import org.apache.http.message.BasicHttpRequest; 055import org.apache.http.protocol.HTTP; 056import org.apache.http.ssl.SSLContextBuilder; 057import org.apache.http.ssl.TrustStrategy; 058 059/** 060 * Main program of the HTTP benchmark. 061 * 062 * 063 * @since 4.0 064 */ 065public class HttpBenchmark { 066 067 private final Config config; 068 069 public static void main(final String[] args) throws Exception { 070 071 final Options options = CommandLineUtils.getOptions(); 072 final CommandLineParser parser = new PosixParser(); 073 final CommandLine cmd = parser.parse(options, args); 074 075 if (args.length == 0 || cmd.hasOption('h') || cmd.getArgs().length != 1) { 076 CommandLineUtils.showUsage(options); 077 System.exit(1); 078 } 079 080 final Config config = new Config(); 081 CommandLineUtils.parseCommandLine(cmd, config); 082 083 if (config.getUrl() == null) { 084 CommandLineUtils.showUsage(options); 085 System.exit(1); 086 } 087 088 final HttpBenchmark httpBenchmark = new HttpBenchmark(config); 089 httpBenchmark.execute(); 090 } 091 092 public HttpBenchmark(final Config config) { 093 super(); 094 this.config = config != null ? config : new Config(); 095 } 096 097 private HttpRequest createRequest() { 098 final URL url = config.getUrl(); 099 HttpEntity entity = null; 100 101 // Prepare requests for each thread 102 if (config.getPayloadFile() != null) { 103 final FileEntity fe = new FileEntity(config.getPayloadFile()); 104 fe.setContentType(config.getContentType()); 105 fe.setChunked(config.isUseChunking()); 106 entity = fe; 107 } else if (config.getPayloadText() != null) { 108 final StringEntity se = new StringEntity(config.getPayloadText(), 109 ContentType.parse(config.getContentType())); 110 se.setChunked(config.isUseChunking()); 111 entity = se; 112 } 113 final HttpVersion ver = config.isUseHttp1_0() ? HttpVersion.HTTP_1_0 : HttpVersion.HTTP_1_1; 114 final HttpRequest request; 115 if ("POST".equals(config.getMethod())) { 116 final BasicHttpEntityEnclosingRequest httppost = 117 new BasicHttpEntityEnclosingRequest("POST", url.getPath(), ver); 118 httppost.setEntity(entity); 119 request = httppost; 120 } else if ("PUT".equals(config.getMethod())) { 121 final BasicHttpEntityEnclosingRequest httpput = 122 new BasicHttpEntityEnclosingRequest("PUT", url.getPath(), ver); 123 httpput.setEntity(entity); 124 request = httpput; 125 } else { 126 String path = url.getPath(); 127 if (url.getQuery() != null && url.getQuery().length() > 0) { 128 path += "?" + url.getQuery(); 129 } else if (path.trim().length() == 0) { 130 path = "/"; 131 } 132 request = new BasicHttpRequest(config.getMethod(), path, ver); 133 } 134 135 if (!config.isKeepAlive()) { 136 request.addHeader(new DefaultHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE)); 137 } 138 139 final String[] headers = config.getHeaders(); 140 if (headers != null) { 141 for (final String s : headers) { 142 final int pos = s.indexOf(':'); 143 if (pos != -1) { 144 final Header header = new DefaultHeader(s.substring(0, pos).trim(), s.substring(pos + 1)); 145 request.addHeader(header); 146 } 147 } 148 } 149 150 if (config.isUseAcceptGZip()) { 151 request.addHeader(new DefaultHeader("Accept-Encoding", "gzip")); 152 } 153 154 if (config.getSoapAction() != null && config.getSoapAction().length() > 0) { 155 request.addHeader(new DefaultHeader("SOAPAction", config.getSoapAction())); 156 } 157 return request; 158 } 159 160 public String execute() throws Exception { 161 final Results results = doExecute(); 162 ResultProcessor.printResults(results); 163 return ""; 164 } 165 166 public Results doExecute() throws Exception { 167 168 final URL url = config.getUrl(); 169 final HttpHost host = new HttpHost(url.getHost(), url.getPort(), url.getProtocol()); 170 171 final ThreadPoolExecutor workerPool = new ThreadPoolExecutor( 172 config.getThreads(), config.getThreads(), 5, TimeUnit.SECONDS, 173 new LinkedBlockingQueue<Runnable>(), 174 new ThreadFactory() { 175 176 @Override 177 public Thread newThread(final Runnable r) { 178 return new Thread(r, "ClientPool"); 179 } 180 181 }); 182 workerPool.prestartAllCoreThreads(); 183 184 SocketFactory socketFactory = null; 185 if ("https".equals(host.getSchemeName())) { 186 final SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); 187 sslContextBuilder.setProtocol("SSL"); 188 if (config.isDisableSSLVerification()) { 189 sslContextBuilder.loadTrustMaterial(null, new TrustStrategy() { 190 191 @Override 192 public boolean isTrusted( 193 final X509Certificate[] chain, final String authType) throws CertificateException { 194 return true; 195 } 196 197 }); 198 } else if (config.getTrustStorePath() != null) { 199 sslContextBuilder.loadTrustMaterial( 200 new File(config.getTrustStorePath()), 201 config.getTrustStorePassword() != null ? config.getTrustStorePassword().toCharArray() : null); 202 } 203 if (config.getIdentityStorePath() != null) { 204 sslContextBuilder.loadKeyMaterial( 205 new File(config.getIdentityStorePath()), 206 config.getIdentityStorePassword() != null ? config.getIdentityStorePassword().toCharArray() : null, 207 config.getIdentityStorePassword() != null ? config.getIdentityStorePassword().toCharArray() : null); 208 } 209 final SSLContext sslContext = sslContextBuilder.build(); 210 socketFactory = sslContext.getSocketFactory(); 211 } 212 213 final BenchmarkWorker[] workers = new BenchmarkWorker[config.getThreads()]; 214 for (int i = 0; i < workers.length; i++) { 215 workers[i] = new BenchmarkWorker( 216 createRequest(), 217 host, 218 socketFactory, 219 config); 220 workerPool.execute(workers[i]); 221 } 222 223 while (workerPool.getCompletedTaskCount() < config.getThreads()) { 224 Thread.yield(); 225 try { 226 Thread.sleep(1000); 227 } catch (final InterruptedException ignore) { 228 } 229 } 230 231 workerPool.shutdown(); 232 return ResultProcessor.collectResults(workers, host, config.getUrl().toString()); 233 } 234 235}