View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.core5.benchmark;
28  
29  import java.io.File;
30  import java.net.URI;
31  import java.net.URISyntaxException;
32  
33  import org.apache.commons.cli.CommandLine;
34  import org.apache.commons.cli.HelpFormatter;
35  import org.apache.commons.cli.Option;
36  import org.apache.commons.cli.Options;
37  import org.apache.hc.core5.http.ContentType;
38  import org.apache.hc.core5.http.Method;
39  import org.apache.hc.core5.util.TimeValue;
40  import org.apache.hc.core5.util.Timeout;
41  
42  public class CommandLineUtils {
43  
44      private CommandLineUtils() {
45          // Do not allow utility class to be instantiated.
46      }
47  
48      public static Options getOptions() {
49          final Option nopt = new Option("n", true, "Number of requests to perform. " +
50                  "The default is to just perform a single request which may lead " +
51                  "to non-representative benchmarking results");
52          nopt.setRequired(false);
53          nopt.setArgName("requests");
54  
55          final Option copt = new Option("c", true, "Number of multiple requests to make at a time. " +
56                  "The default is to just execute a single request");
57          copt.setRequired(false);
58          copt.setArgName("concurrency");
59  
60          final Option topt = new Option("t", true, "Seconds to max. to spend on benchmarking");
61          topt.setRequired(false);
62          topt.setArgName("time-limit");
63  
64          final Option sopt = new Option("s", true, "Seconds to max. wait for each response. Default is 60 seconds");
65          sopt.setRequired(false);
66          sopt.setArgName("socket-Timeout");
67  
68          final Option popt = new Option("p", true, "File containing data to enclose in the request");
69          popt.setRequired(false);
70          popt.setArgName("Payload file");
71  
72          final Option Topt = new Option("T", true, "Content-type header to use for enclosed request data");
73          Topt.setRequired(false);
74          Topt.setArgName("content-type");
75  
76          final Option vopt = new Option("v", true, "Set verbosity level: " +
77                  "1 prints warnings and errors, " +
78                  "2 prints response codes, " +
79                  "3 prints message headers, " +
80                  "4 prints HTTP/2 frame info, " +
81                  "5 prints HTTP/2 flow control events, " +
82                  "6 prints response content");
83          vopt.setRequired(false);
84          vopt.setArgName("verbosity");
85  
86          final Option iopt = new Option("i", false, "Use HEAD instead of GET");
87          iopt.setRequired(false);
88  
89          final Option Hopt = new Option("H", true, "Add arbitrary header line, " +
90                  "eg. 'Accept-Encoding: gzip' inserted after all normal " +
91                  "header lines. (repeatable as -H \"h1: v1\",\"h2: v2\" etc)");
92          Hopt.setRequired(false);
93          Hopt.setArgName("header");
94  
95          final Option kopt = new Option("k", false, "Use HTTP KeepAlive feature. Default is no KeepAlive");
96          kopt.setRequired(false);
97  
98          final Option mopt = new Option("m", true, "HTTP Method. Default is GET or POST if the request to enclose data");
99          mopt.setRequired(false);
100         mopt.setArgName("HTTP method");
101 
102         // HttpCore specific options
103 
104         final Option uopt = new Option("u", false, "Chunk entity. Default is false");
105         uopt.setRequired(false);
106 
107         final Option xopt = new Option("x", false, "Use Expect-Continue. Default is false");
108         xopt.setRequired(false);
109 
110         final Option gopt = new Option("g", false, "Accept GZip. Default is false");
111         gopt.setRequired(false);
112 
113         final Option http2opt = new Option("2", false, "Force HTTP/2");
114         gopt.setRequired(false);
115 
116         final Option hopt = new Option("h", false, "Display usage information");
117         nopt.setRequired(false);
118 
119         final Options options = new Options();
120         options.addOption(nopt);
121         options.addOption(copt);
122         options.addOption(topt);
123         options.addOption(sopt);
124         options.addOption(popt);
125         options.addOption(Topt);
126         options.addOption(vopt);
127         options.addOption(iopt);
128         options.addOption(Hopt);
129         options.addOption(kopt);
130         options.addOption(mopt);
131 
132         // HttpCore specific options
133 
134         options.addOption(uopt);
135         options.addOption(xopt);
136         options.addOption(gopt);
137         options.addOption(http2opt);
138 
139         options.addOption(hopt);
140         return options;
141     }
142 
143     public static BenchmarkConfig parseCommandLine(final CommandLine cmd) {
144         final BenchmarkConfig.Builder builder = new BenchmarkConfig.Builder();
145         if (cmd.hasOption('n')) {
146             final String s = cmd.getOptionValue('n');
147             try {
148                 builder.setRequests(Integer.parseInt(s));
149             } catch (final NumberFormatException ex) {
150                 printError("Invalid number of requests: " + s);
151             }
152         }
153 
154         if (cmd.hasOption('c')) {
155             final String s = cmd.getOptionValue('c');
156             try {
157                 builder.setConcurrencyLevel(Integer.parseInt(s));
158             } catch (final NumberFormatException ex) {
159                 printError("Invalid number for concurrency: " + s);
160             }
161         }
162 
163         if (cmd.hasOption('t')) {
164             final String t = cmd.getOptionValue('t');
165             try {
166                 builder.setTimeLimit(TimeValue.ofSeconds(Integer.parseInt(t)));
167             } catch (final NumberFormatException ex) {
168                 printError("Invalid time limit: " + t);
169             }
170         }
171 
172         if (cmd.hasOption('s')) {
173             final String s = cmd.getOptionValue('s');
174             try {
175                 builder.setSocketTimeout(Timeout.ofMilliseconds(Integer.parseInt(s)));
176             } catch (final NumberFormatException ex) {
177                 printError("Invalid socket timeout: " + s);
178             }
179         }
180 
181         if (cmd.hasOption('p')) {
182             final File file = new File(cmd.getOptionValue('p'));
183             if (!file.exists()) {
184                 printError("File not found: " + file);
185             }
186             builder.setPayloadFile(file);
187         }
188 
189         if (cmd.hasOption('T')) {
190             builder.setContentType(ContentType.parse(cmd.getOptionValue('T')));
191         }
192 
193         if (cmd.hasOption('v')) {
194             final String s = cmd.getOptionValue('v');
195             try {
196                 builder.setVerbosity(Integer.parseInt(s));
197             } catch (final NumberFormatException ex) {
198                 printError("Invalid verbosity level: " + s);
199             }
200         }
201 
202         if (cmd.hasOption('i')) {
203             builder.setHeadInsteadOfGet(true);
204         }
205 
206         if (cmd.hasOption('H')) {
207             final String headerStr = cmd.getOptionValue('H');
208             builder.setHeaders(headerStr.split(","));
209         }
210 
211         if (cmd.hasOption('k')) {
212             builder.setKeepAlive(true);
213         }
214 
215         if (cmd.hasOption('m')) {
216             builder.setMethod(cmd.getOptionValue('m'));
217         } else if (cmd.hasOption('p')) {
218             builder.setMethod(Method.POST.name());
219         }
220 
221         if (cmd.hasOption('u')) {
222             builder.setUseChunking(true);
223         }
224 
225         if (cmd.hasOption('x')) {
226             builder.setUseExpectContinue(true);
227         }
228 
229         if (cmd.hasOption('g')) {
230             builder.setUseAcceptGZip(true);
231         }
232 
233         if (cmd.hasOption('2')) {
234             builder.setForceHttp2(true);
235         }
236 
237         final String[] cmdargs = cmd.getArgs();
238         if (cmdargs.length > 0) {
239             try {
240                 builder.setUri(new URI(cmdargs[0]));
241             } catch (final URISyntaxException e) {
242                 printError("Invalid request URI: " + cmdargs[0]);
243             }
244         }
245 
246         return builder.build();
247     }
248 
249     static void showUsage(final Options options) {
250         final HelpFormatter formatter = new HelpFormatter();
251         formatter.printHelp("HttpBenchmark [options] [http://]hostname[:port]/path?query", options);
252     }
253 
254     static void printError(final String msg) {
255         System.err.println(msg);
256         showUsage(getOptions());
257         System.exit(-1);
258     }
259 }