1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
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
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
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 }