1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24 #include "tool_setup.h"
25
26 #include "strcase.h"
27
28 #define ENABLE_CURLX_PRINTF
29 /* use our own printf() functions */
30 #include "curlx.h"
31
32 #include "tool_binmode.h"
33 #include "tool_cfgable.h"
34 #include "tool_cb_prg.h"
35 #include "tool_filetime.h"
36 #include "tool_formparse.h"
37 #include "tool_getparam.h"
38 #include "tool_helpers.h"
39 #include "tool_libinfo.h"
40 #include "tool_msgs.h"
41 #include "tool_paramhlp.h"
42 #include "tool_parsecfg.h"
43 #include "tool_main.h"
44 #include "dynbuf.h"
45 #include "tool_stderr.h"
46 #include "var.h"
47
48 #include "memdebug.h" /* keep this as LAST include */
49
50 #ifdef MSDOS
51 # define USE_WATT32
52 #endif
53
54 #define ALLOW_BLANK TRUE
55 #define DENY_BLANK FALSE
56
getstr(char ** str,const char * val,bool allowblank)57 static ParameterError getstr(char **str, const char *val, bool allowblank)
58 {
59 if(*str) {
60 free(*str);
61 *str = NULL;
62 }
63 if(val) {
64 if(!allowblank && !val[0])
65 return PARAM_BLANK_STRING;
66
67 *str = strdup(val);
68 if(!*str)
69 return PARAM_NO_MEM;
70 }
71 return PARAM_OK;
72 }
73
74 /* one enum for every command line option. The name is the verbatim long
75 option name, but in uppercase with periods and minuses replaced with
76 underscores using a "C_" prefix. */
77 typedef enum {
78 C_ABSTRACT_UNIX_SOCKET,
79 C_ALPN,
80 C_ALT_SVC,
81 C_ANYAUTH,
82 C_APPEND,
83 C_AWS_SIGV4,
84 C_BASIC,
85 C_BUFFER,
86 C_CA_NATIVE,
87 C_CACERT,
88 C_CAPATH,
89 C_CERT,
90 C_CERT_STATUS,
91 C_CERT_TYPE,
92 C_CIPHERS,
93 C_CLOBBER,
94 C_COMPRESSED,
95 C_COMPRESSED_SSH,
96 C_CONFIG,
97 C_CONNECT_TIMEOUT,
98 C_CONNECT_TO,
99 C_CONTINUE_AT,
100 C_COOKIE,
101 C_COOKIE_JAR,
102 C_CREATE_DIRS,
103 C_CREATE_FILE_MODE,
104 C_CRLF,
105 C_CRLFILE,
106 C_CURVES,
107 C_DATA,
108 C_DATA_ASCII,
109 C_DATA_BINARY,
110 C_DATA_RAW,
111 C_DATA_URLENCODE,
112 C_DELEGATION,
113 C_DIGEST,
114 C_DISABLE,
115 C_DISABLE_EPRT,
116 C_DISABLE_EPSV,
117 C_DISALLOW_USERNAME_IN_URL,
118 C_DNS_INTERFACE,
119 C_DNS_IPV4_ADDR,
120 C_DNS_IPV6_ADDR,
121 C_DNS_SERVERS,
122 C_DOH_CERT_STATUS,
123 C_DOH_INSECURE,
124 C_DOH_URL,
125 C_DUMP_HEADER,
126 C_ECH,
127 C_EGD_FILE,
128 C_ENGINE,
129 C_EPRT,
130 C_EPSV,
131 C_ETAG_COMPARE,
132 C_ETAG_SAVE,
133 C_EXPECT100_TIMEOUT,
134 C_FAIL,
135 C_FAIL_EARLY,
136 C_FAIL_WITH_BODY,
137 C_FALSE_START,
138 C_FORM,
139 C_FORM_ESCAPE,
140 C_FORM_STRING,
141 C_FTP_ACCOUNT,
142 C_FTP_ALTERNATIVE_TO_USER,
143 C_FTP_CREATE_DIRS,
144 C_FTP_METHOD,
145 C_FTP_PASV,
146 C_FTP_PORT,
147 C_FTP_PRET,
148 C_FTP_SKIP_PASV_IP,
149 C_FTP_SSL,
150 C_FTP_SSL_CCC,
151 C_FTP_SSL_CCC_MODE,
152 C_FTP_SSL_CONTROL,
153 C_FTP_SSL_REQD,
154 C_GET,
155 C_GLOBOFF,
156 C_HAPPY_EYEBALLS_TIMEOUT_MS,
157 C_HAPROXY_CLIENTIP,
158 C_HAPROXY_PROTOCOL,
159 C_HEAD,
160 C_HEADER,
161 C_HELP,
162 C_HOSTPUBMD5,
163 C_HOSTPUBSHA256,
164 C_HSTS,
165 C_HTTP0_9,
166 C_HTTP1_0,
167 C_HTTP1_1,
168 C_HTTP2,
169 C_HTTP2_PRIOR_KNOWLEDGE,
170 C_HTTP3,
171 C_HTTP3_ONLY,
172 C_IGNORE_CONTENT_LENGTH,
173 C_INCLUDE,
174 C_INSECURE,
175 C_INTERFACE,
176 C_IPFS_GATEWAY,
177 C_IPV4,
178 C_IPV6,
179 C_JSON,
180 C_JUNK_SESSION_COOKIES,
181 C_KEEPALIVE,
182 C_KEEPALIVE_TIME,
183 C_KEY,
184 C_KEY_TYPE,
185 C_KRB,
186 C_KRB4,
187 C_LIBCURL,
188 C_LIMIT_RATE,
189 C_LIST_ONLY,
190 C_LOCAL_PORT,
191 C_LOCATION,
192 C_LOCATION_TRUSTED,
193 C_LOGIN_OPTIONS,
194 C_MAIL_AUTH,
195 C_MAIL_FROM,
196 C_MAIL_RCPT,
197 C_MAIL_RCPT_ALLOWFAILS,
198 C_MANUAL,
199 C_MAX_FILESIZE,
200 C_MAX_REDIRS,
201 C_MAX_TIME,
202 C_METALINK,
203 C_NEGOTIATE,
204 C_NETRC,
205 C_NETRC_FILE,
206 C_NETRC_OPTIONAL,
207 C_NEXT,
208 C_NOPROXY,
209 C_NPN,
210 C_NTLM,
211 C_NTLM_WB,
212 C_OAUTH2_BEARER,
213 C_OUTPUT,
214 C_OUTPUT_DIR,
215 C_PARALLEL,
216 C_PARALLEL_IMMEDIATE,
217 C_PARALLEL_MAX,
218 C_PASS,
219 C_PATH_AS_IS,
220 C_PINNEDPUBKEY,
221 C_POST301,
222 C_POST302,
223 C_POST303,
224 C_PREPROXY,
225 C_PROGRESS_BAR,
226 C_PROGRESS_METER,
227 C_PROTO,
228 C_PROTO_DEFAULT,
229 C_PROTO_REDIR,
230 C_PROXY,
231 C_PROXY_ANYAUTH,
232 C_PROXY_BASIC,
233 C_PROXY_CA_NATIVE,
234 C_PROXY_CACERT,
235 C_PROXY_CAPATH,
236 C_PROXY_CERT,
237 C_PROXY_CERT_TYPE,
238 C_PROXY_CIPHERS,
239 C_PROXY_CRLFILE,
240 C_PROXY_DIGEST,
241 C_PROXY_HEADER,
242 C_PROXY_HTTP2,
243 C_PROXY_INSECURE,
244 C_PROXY_KEY,
245 C_PROXY_KEY_TYPE,
246 C_PROXY_NEGOTIATE,
247 C_PROXY_NTLM,
248 C_PROXY_PASS,
249 C_PROXY_PINNEDPUBKEY,
250 C_PROXY_SERVICE_NAME,
251 C_PROXY_SSL_ALLOW_BEAST,
252 C_PROXY_SSL_AUTO_CLIENT_CERT,
253 C_PROXY_TLS13_CIPHERS,
254 C_PROXY_TLSAUTHTYPE,
255 C_PROXY_TLSPASSWORD,
256 C_PROXY_TLSUSER,
257 C_PROXY_TLSV1,
258 C_PROXY_USER,
259 C_PROXY1_0,
260 C_PROXYTUNNEL,
261 C_PUBKEY,
262 C_QUOTE,
263 C_RANDOM_FILE,
264 C_RANGE,
265 C_RATE,
266 C_RAW,
267 C_REFERER,
268 C_REMOTE_HEADER_NAME,
269 C_REMOTE_NAME,
270 C_REMOTE_NAME_ALL,
271 C_REMOTE_TIME,
272 C_REMOVE_ON_ERROR,
273 C_REQUEST,
274 C_REQUEST_TARGET,
275 C_RESOLVE,
276 C_RETRY,
277 C_RETRY_ALL_ERRORS,
278 C_RETRY_CONNREFUSED,
279 C_RETRY_DELAY,
280 C_RETRY_MAX_TIME,
281 C_SASL_AUTHZID,
282 C_SASL_IR,
283 C_SERVICE_NAME,
284 C_SESSIONID,
285 C_SHOW_ERROR,
286 C_SILENT,
287 C_SOCKS4,
288 C_SOCKS4A,
289 C_SOCKS5,
290 C_SOCKS5_BASIC,
291 C_SOCKS5_GSSAPI,
292 C_SOCKS5_GSSAPI_NEC,
293 C_SOCKS5_GSSAPI_SERVICE,
294 C_SOCKS5_HOSTNAME,
295 C_SPEED_LIMIT,
296 C_SPEED_TIME,
297 C_SSL,
298 C_SSL_ALLOW_BEAST,
299 C_SSL_AUTO_CLIENT_CERT,
300 C_SSL_NO_REVOKE,
301 C_SSL_REQD,
302 C_SSL_REVOKE_BEST_EFFORT,
303 C_SSLV2,
304 C_SSLV3,
305 C_STDERR,
306 C_STYLED_OUTPUT,
307 C_SUPPRESS_CONNECT_HEADERS,
308 C_TCP_FASTOPEN,
309 C_TCP_NODELAY,
310 C_TELNET_OPTION,
311 C_TEST_EVENT,
312 C_TFTP_BLKSIZE,
313 C_TFTP_NO_OPTIONS,
314 C_TIME_COND,
315 C_TLS_MAX,
316 C_TLS13_CIPHERS,
317 C_TLSAUTHTYPE,
318 C_TLSPASSWORD,
319 C_TLSUSER,
320 C_TLSV1,
321 C_TLSV1_0,
322 C_TLSV1_1,
323 C_TLSV1_2,
324 C_TLSV1_3,
325 C_TR_ENCODING,
326 C_TRACE,
327 C_TRACE_ASCII,
328 C_TRACE_CONFIG,
329 C_TRACE_IDS,
330 C_TRACE_TIME,
331 C_UNIX_SOCKET,
332 C_UPLOAD_FILE,
333 C_URL,
334 C_URL_QUERY,
335 C_USE_ASCII,
336 C_USER,
337 C_USER_AGENT,
338 C_VARIABLE,
339 C_VERBOSE,
340 C_VERSION,
341 C_WDEBUG,
342 C_WRITE_OUT,
343 C_XATTR
344 } cmdline_t;
345
346 struct LongShort {
347 const char *lname; /* long name option */
348 enum {
349 ARG_NONE, /* stand-alone but not a boolean */
350 ARG_BOOL, /* accepts a --no-[name] prefix */
351 ARG_STRG, /* requires an argument */
352 ARG_FILE /* requires an argument, usually a file name */
353 } desc;
354 char letter; /* short name option or ' ' */
355 cmdline_t cmd;
356 };
357
358 /* this array MUST be alphasorted based on the 'lname' */
359 static const struct LongShort aliases[]= {
360 {"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET},
361 {"alpn", ARG_BOOL, ' ', C_ALPN},
362 {"alt-svc", ARG_STRG, ' ', C_ALT_SVC},
363 {"anyauth", ARG_BOOL, ' ', C_ANYAUTH},
364 {"append", ARG_BOOL, 'a', C_APPEND},
365 {"aws-sigv4", ARG_STRG, ' ', C_AWS_SIGV4},
366 {"basic", ARG_BOOL, ' ', C_BASIC},
367 {"buffer", ARG_BOOL, 'N', C_BUFFER},
368 {"ca-native", ARG_BOOL, ' ', C_CA_NATIVE},
369 {"cacert", ARG_FILE, ' ', C_CACERT},
370 {"capath", ARG_FILE, ' ', C_CAPATH},
371 {"cert", ARG_FILE, 'E', C_CERT},
372 {"cert-status", ARG_BOOL, ' ', C_CERT_STATUS},
373 {"cert-type", ARG_STRG, ' ', C_CERT_TYPE},
374 {"ciphers", ARG_STRG, ' ', C_CIPHERS},
375 {"clobber", ARG_BOOL, ' ', C_CLOBBER},
376 {"compressed", ARG_BOOL, ' ', C_COMPRESSED},
377 {"compressed-ssh", ARG_BOOL, ' ', C_COMPRESSED_SSH},
378 {"config", ARG_FILE, 'K', C_CONFIG},
379 {"connect-timeout", ARG_STRG, ' ', C_CONNECT_TIMEOUT},
380 {"connect-to", ARG_STRG, ' ', C_CONNECT_TO},
381 {"continue-at", ARG_STRG, 'C', C_CONTINUE_AT},
382 {"cookie", ARG_STRG, 'b', C_COOKIE},
383 {"cookie-jar", ARG_STRG, 'c', C_COOKIE_JAR},
384 {"create-dirs", ARG_BOOL, ' ', C_CREATE_DIRS},
385 {"create-file-mode", ARG_STRG, ' ', C_CREATE_FILE_MODE},
386 {"crlf", ARG_BOOL, ' ', C_CRLF},
387 {"crlfile", ARG_FILE, ' ', C_CRLFILE},
388 {"curves", ARG_STRG, ' ', C_CURVES},
389 {"data", ARG_STRG, 'd', C_DATA},
390 {"data-ascii", ARG_STRG, ' ', C_DATA_ASCII},
391 {"data-binary", ARG_STRG, ' ', C_DATA_BINARY},
392 {"data-raw", ARG_STRG, ' ', C_DATA_RAW},
393 {"data-urlencode", ARG_STRG, ' ', C_DATA_URLENCODE},
394 {"delegation", ARG_STRG, ' ', C_DELEGATION},
395 {"digest", ARG_BOOL, ' ', C_DIGEST},
396 {"disable", ARG_BOOL, 'q', C_DISABLE},
397 {"disable-eprt", ARG_BOOL, ' ', C_DISABLE_EPRT},
398 {"disable-epsv", ARG_BOOL, ' ', C_DISABLE_EPSV},
399 {"disallow-username-in-url", ARG_BOOL, ' ', C_DISALLOW_USERNAME_IN_URL},
400 {"dns-interface", ARG_STRG, ' ', C_DNS_INTERFACE},
401 {"dns-ipv4-addr", ARG_STRG, ' ', C_DNS_IPV4_ADDR},
402 {"dns-ipv6-addr", ARG_STRG, ' ', C_DNS_IPV6_ADDR},
403 {"dns-servers", ARG_STRG, ' ', C_DNS_SERVERS},
404 {"doh-cert-status", ARG_BOOL, ' ', C_DOH_CERT_STATUS},
405 {"doh-insecure", ARG_BOOL, ' ', C_DOH_INSECURE},
406 {"doh-url" , ARG_STRG, ' ', C_DOH_URL},
407 {"dump-header", ARG_FILE, 'D', C_DUMP_HEADER},
408 {"ech", ARG_STRG, ' ', C_ECH},
409 {"egd-file", ARG_STRG, ' ', C_EGD_FILE},
410 {"engine", ARG_STRG, ' ', C_ENGINE},
411 {"eprt", ARG_BOOL, ' ', C_EPRT},
412 {"epsv", ARG_BOOL, ' ', C_EPSV},
413 {"etag-compare", ARG_FILE, ' ', C_ETAG_COMPARE},
414 {"etag-save", ARG_FILE, ' ', C_ETAG_SAVE},
415 {"expect100-timeout", ARG_STRG, ' ', C_EXPECT100_TIMEOUT},
416 {"fail", ARG_BOOL, 'f', C_FAIL},
417 {"fail-early", ARG_BOOL, ' ', C_FAIL_EARLY},
418 {"fail-with-body", ARG_BOOL, ' ', C_FAIL_WITH_BODY},
419 {"false-start", ARG_BOOL, ' ', C_FALSE_START},
420 {"form", ARG_STRG, 'F', C_FORM},
421 {"form-escape", ARG_BOOL, ' ', C_FORM_ESCAPE},
422 {"form-string", ARG_STRG, ' ', C_FORM_STRING},
423 {"ftp-account", ARG_STRG, ' ', C_FTP_ACCOUNT},
424 {"ftp-alternative-to-user", ARG_STRG, ' ', C_FTP_ALTERNATIVE_TO_USER},
425 {"ftp-create-dirs", ARG_BOOL, ' ', C_FTP_CREATE_DIRS},
426 {"ftp-method", ARG_STRG, ' ', C_FTP_METHOD},
427 {"ftp-pasv", ARG_BOOL, ' ', C_FTP_PASV},
428 {"ftp-port", ARG_STRG, 'P', C_FTP_PORT},
429 {"ftp-pret", ARG_BOOL, ' ', C_FTP_PRET},
430 {"ftp-skip-pasv-ip", ARG_BOOL, ' ', C_FTP_SKIP_PASV_IP},
431 {"ftp-ssl", ARG_BOOL, ' ', C_FTP_SSL},
432 {"ftp-ssl-ccc", ARG_BOOL, ' ', C_FTP_SSL_CCC},
433 {"ftp-ssl-ccc-mode", ARG_STRG, ' ', C_FTP_SSL_CCC_MODE},
434 {"ftp-ssl-control", ARG_BOOL, ' ', C_FTP_SSL_CONTROL},
435 {"ftp-ssl-reqd", ARG_BOOL, ' ', C_FTP_SSL_REQD},
436 {"get", ARG_BOOL, 'G', C_GET},
437 {"globoff", ARG_BOOL, 'g', C_GLOBOFF},
438 {"happy-eyeballs-timeout-ms", ARG_STRG, ' ', C_HAPPY_EYEBALLS_TIMEOUT_MS},
439 {"haproxy-clientip", ARG_STRG, ' ', C_HAPROXY_CLIENTIP},
440 {"haproxy-protocol", ARG_BOOL, ' ', C_HAPROXY_PROTOCOL},
441 {"head", ARG_BOOL, 'I', C_HEAD},
442 {"header", ARG_STRG, 'H', C_HEADER},
443 {"help", ARG_BOOL, 'h', C_HELP},
444 {"hostpubmd5", ARG_STRG, ' ', C_HOSTPUBMD5},
445 {"hostpubsha256", ARG_STRG, ' ', C_HOSTPUBSHA256},
446 {"hsts", ARG_STRG, ' ', C_HSTS},
447 {"http0.9", ARG_BOOL, ' ', C_HTTP0_9},
448 {"http1.0", ARG_NONE, '0', C_HTTP1_0},
449 {"http1.1", ARG_NONE, ' ', C_HTTP1_1},
450 {"http2", ARG_NONE, ' ', C_HTTP2},
451 {"http2-prior-knowledge", ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE},
452 {"http3", ARG_NONE, ' ', C_HTTP3},
453 {"http3-only", ARG_NONE, ' ', C_HTTP3_ONLY},
454 {"ignore-content-length", ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH},
455 {"include", ARG_BOOL, 'i', C_INCLUDE},
456 {"insecure", ARG_BOOL, 'k', C_INSECURE},
457 {"interface", ARG_STRG, ' ', C_INTERFACE},
458 {"ipfs-gateway", ARG_STRG, ' ', C_IPFS_GATEWAY},
459 {"ipv4", ARG_NONE, '4', C_IPV4},
460 {"ipv6", ARG_NONE, '6', C_IPV6},
461 {"json", ARG_STRG, ' ', C_JSON},
462 {"junk-session-cookies", ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
463 {"keepalive", ARG_BOOL, ' ', C_KEEPALIVE},
464 {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME},
465 {"key", ARG_FILE, ' ', C_KEY},
466 {"key-type", ARG_STRG, ' ', C_KEY_TYPE},
467 {"krb", ARG_STRG, ' ', C_KRB},
468 {"krb4", ARG_STRG, ' ', C_KRB4},
469 {"libcurl", ARG_STRG, ' ', C_LIBCURL},
470 {"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE},
471 {"list-only", ARG_BOOL, 'l', C_LIST_ONLY},
472 {"local-port", ARG_STRG, ' ', C_LOCAL_PORT},
473 {"location", ARG_BOOL, 'L', C_LOCATION},
474 {"location-trusted", ARG_BOOL, ' ', C_LOCATION_TRUSTED},
475 {"login-options", ARG_STRG, ' ', C_LOGIN_OPTIONS},
476 {"mail-auth", ARG_STRG, ' ', C_MAIL_AUTH},
477 {"mail-from", ARG_STRG, ' ', C_MAIL_FROM},
478 {"mail-rcpt", ARG_STRG, ' ', C_MAIL_RCPT},
479 {"mail-rcpt-allowfails", ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS},
480 {"manual", ARG_BOOL, 'M', C_MANUAL},
481 {"max-filesize", ARG_STRG, ' ', C_MAX_FILESIZE},
482 {"max-redirs", ARG_STRG, ' ', C_MAX_REDIRS},
483 {"max-time", ARG_STRG, 'm', C_MAX_TIME},
484 {"metalink", ARG_BOOL, ' ', C_METALINK},
485 {"negotiate", ARG_BOOL, ' ', C_NEGOTIATE},
486 {"netrc", ARG_BOOL, 'n', C_NETRC},
487 {"netrc-file", ARG_FILE, ' ', C_NETRC_FILE},
488 {"netrc-optional", ARG_BOOL, ' ', C_NETRC_OPTIONAL},
489 {"next", ARG_NONE, ':', C_NEXT},
490 {"noproxy", ARG_STRG, ' ', C_NOPROXY},
491 {"npn", ARG_BOOL, ' ', C_NPN},
492 {"ntlm", ARG_BOOL, ' ', C_NTLM},
493 {"ntlm-wb", ARG_BOOL, ' ', C_NTLM_WB},
494 {"oauth2-bearer", ARG_STRG, ' ', C_OAUTH2_BEARER},
495 {"output", ARG_FILE, 'o', C_OUTPUT},
496 {"output-dir", ARG_STRG, ' ', C_OUTPUT_DIR},
497 {"parallel", ARG_BOOL, 'Z', C_PARALLEL},
498 {"parallel-immediate", ARG_BOOL, ' ', C_PARALLEL_IMMEDIATE},
499 {"parallel-max", ARG_STRG, ' ', C_PARALLEL_MAX},
500 {"pass", ARG_STRG, ' ', C_PASS},
501 {"path-as-is", ARG_BOOL, ' ', C_PATH_AS_IS},
502 {"pinnedpubkey", ARG_STRG, ' ', C_PINNEDPUBKEY},
503 {"post301", ARG_BOOL, ' ', C_POST301},
504 {"post302", ARG_BOOL, ' ', C_POST302},
505 {"post303", ARG_BOOL, ' ', C_POST303},
506 {"preproxy", ARG_STRG, ' ', C_PREPROXY},
507 {"progress-bar", ARG_BOOL, '#', C_PROGRESS_BAR},
508 {"progress-meter", ARG_BOOL, ' ', C_PROGRESS_METER},
509 {"proto", ARG_STRG, ' ', C_PROTO},
510 {"proto-default", ARG_STRG, ' ', C_PROTO_DEFAULT},
511 {"proto-redir", ARG_STRG, ' ', C_PROTO_REDIR},
512 {"proxy", ARG_STRG, 'x', C_PROXY},
513 {"proxy-anyauth", ARG_BOOL, ' ', C_PROXY_ANYAUTH},
514 {"proxy-basic", ARG_BOOL, ' ', C_PROXY_BASIC},
515 {"proxy-ca-native", ARG_BOOL, ' ', C_PROXY_CA_NATIVE},
516 {"proxy-cacert", ARG_FILE, ' ', C_PROXY_CACERT},
517 {"proxy-capath", ARG_FILE, ' ', C_PROXY_CAPATH},
518 {"proxy-cert", ARG_FILE, ' ', C_PROXY_CERT},
519 {"proxy-cert-type", ARG_STRG, ' ', C_PROXY_CERT_TYPE},
520 {"proxy-ciphers", ARG_STRG, ' ', C_PROXY_CIPHERS},
521 {"proxy-crlfile", ARG_FILE, ' ', C_PROXY_CRLFILE},
522 {"proxy-digest", ARG_BOOL, ' ', C_PROXY_DIGEST},
523 {"proxy-header", ARG_STRG, ' ', C_PROXY_HEADER},
524 {"proxy-http2", ARG_BOOL, ' ', C_PROXY_HTTP2},
525 {"proxy-insecure", ARG_BOOL, ' ', C_PROXY_INSECURE},
526 {"proxy-key", ARG_FILE, ' ', C_PROXY_KEY},
527 {"proxy-key-type", ARG_STRG, ' ', C_PROXY_KEY_TYPE},
528 {"proxy-negotiate", ARG_BOOL, ' ', C_PROXY_NEGOTIATE},
529 {"proxy-ntlm", ARG_BOOL, ' ', C_PROXY_NTLM},
530 {"proxy-pass", ARG_STRG, ' ', C_PROXY_PASS},
531 {"proxy-pinnedpubkey", ARG_STRG, ' ', C_PROXY_PINNEDPUBKEY},
532 {"proxy-service-name", ARG_STRG, ' ', C_PROXY_SERVICE_NAME},
533 {"proxy-ssl-allow-beast", ARG_BOOL, ' ', C_PROXY_SSL_ALLOW_BEAST},
534 {"proxy-ssl-auto-client-cert", ARG_BOOL, ' ', C_PROXY_SSL_AUTO_CLIENT_CERT},
535 {"proxy-tls13-ciphers", ARG_STRG, ' ', C_PROXY_TLS13_CIPHERS},
536 {"proxy-tlsauthtype", ARG_STRG, ' ', C_PROXY_TLSAUTHTYPE},
537 {"proxy-tlspassword", ARG_STRG, ' ', C_PROXY_TLSPASSWORD},
538 {"proxy-tlsuser", ARG_STRG, ' ', C_PROXY_TLSUSER},
539 {"proxy-tlsv1", ARG_NONE, ' ', C_PROXY_TLSV1},
540 {"proxy-user", ARG_STRG, 'U', C_PROXY_USER},
541 {"proxy1.0", ARG_STRG, ' ', C_PROXY1_0},
542 {"proxytunnel", ARG_BOOL, 'p', C_PROXYTUNNEL},
543 {"pubkey", ARG_STRG, ' ', C_PUBKEY},
544 {"quote", ARG_STRG, 'Q', C_QUOTE},
545 {"random-file", ARG_FILE, ' ', C_RANDOM_FILE},
546 {"range", ARG_STRG, 'r', C_RANGE},
547 {"rate", ARG_STRG, ' ', C_RATE},
548 {"raw", ARG_BOOL, ' ', C_RAW},
549 {"referer", ARG_STRG, 'e', C_REFERER},
550 {"remote-header-name", ARG_BOOL, 'J', C_REMOTE_HEADER_NAME},
551 {"remote-name", ARG_BOOL, 'O', C_REMOTE_NAME},
552 {"remote-name-all", ARG_BOOL, ' ', C_REMOTE_NAME_ALL},
553 {"remote-time", ARG_BOOL, 'R', C_REMOTE_TIME},
554 {"remove-on-error", ARG_BOOL, ' ', C_REMOVE_ON_ERROR},
555 {"request", ARG_STRG, 'X', C_REQUEST},
556 {"request-target", ARG_STRG, ' ', C_REQUEST_TARGET},
557 {"resolve", ARG_STRG, ' ', C_RESOLVE},
558 {"retry", ARG_STRG, ' ', C_RETRY},
559 {"retry-all-errors", ARG_BOOL, ' ', C_RETRY_ALL_ERRORS},
560 {"retry-connrefused", ARG_BOOL, ' ', C_RETRY_CONNREFUSED},
561 {"retry-delay", ARG_STRG, ' ', C_RETRY_DELAY},
562 {"retry-max-time", ARG_STRG, ' ', C_RETRY_MAX_TIME},
563 {"sasl-authzid", ARG_STRG, ' ', C_SASL_AUTHZID},
564 {"sasl-ir", ARG_BOOL, ' ', C_SASL_IR},
565 {"service-name", ARG_STRG, ' ', C_SERVICE_NAME},
566 {"sessionid", ARG_BOOL, ' ', C_SESSIONID},
567 {"show-error", ARG_BOOL, 'S', C_SHOW_ERROR},
568 {"silent", ARG_BOOL, 's', C_SILENT},
569 {"socks4", ARG_STRG, ' ', C_SOCKS4},
570 {"socks4a", ARG_STRG, ' ', C_SOCKS4A},
571 {"socks5", ARG_STRG, ' ', C_SOCKS5},
572 {"socks5-basic", ARG_BOOL, ' ', C_SOCKS5_BASIC},
573 {"socks5-gssapi", ARG_BOOL, ' ', C_SOCKS5_GSSAPI},
574 {"socks5-gssapi-nec", ARG_BOOL, ' ', C_SOCKS5_GSSAPI_NEC},
575 {"socks5-gssapi-service", ARG_STRG, ' ', C_SOCKS5_GSSAPI_SERVICE},
576 {"socks5-hostname", ARG_STRG, ' ', C_SOCKS5_HOSTNAME},
577 {"speed-limit", ARG_STRG, 'Y', C_SPEED_LIMIT},
578 {"speed-time", ARG_STRG, 'y', C_SPEED_TIME},
579 {"ssl", ARG_BOOL, ' ', C_SSL},
580 {"ssl-allow-beast", ARG_BOOL, ' ', C_SSL_ALLOW_BEAST},
581 {"ssl-auto-client-cert", ARG_BOOL, ' ', C_SSL_AUTO_CLIENT_CERT},
582 {"ssl-no-revoke", ARG_BOOL, ' ', C_SSL_NO_REVOKE},
583 {"ssl-reqd", ARG_BOOL, ' ', C_SSL_REQD},
584 {"ssl-revoke-best-effort", ARG_BOOL, ' ', C_SSL_REVOKE_BEST_EFFORT},
585 {"sslv2", ARG_NONE, '2', C_SSLV2},
586 {"sslv3", ARG_NONE, '3', C_SSLV3},
587 {"stderr", ARG_FILE, ' ', C_STDERR},
588 {"styled-output", ARG_BOOL, ' ', C_STYLED_OUTPUT},
589 {"suppress-connect-headers", ARG_BOOL, ' ', C_SUPPRESS_CONNECT_HEADERS},
590 {"tcp-fastopen", ARG_BOOL, ' ', C_TCP_FASTOPEN},
591 {"tcp-nodelay", ARG_BOOL, ' ', C_TCP_NODELAY},
592 {"telnet-option", ARG_STRG, 't', C_TELNET_OPTION},
593 {"test-event", ARG_BOOL, ' ', C_TEST_EVENT},
594 {"tftp-blksize", ARG_STRG, ' ', C_TFTP_BLKSIZE},
595 {"tftp-no-options", ARG_BOOL, ' ', C_TFTP_NO_OPTIONS},
596 {"time-cond", ARG_STRG, 'z', C_TIME_COND},
597 {"tls-max", ARG_STRG, ' ', C_TLS_MAX},
598 {"tls13-ciphers", ARG_STRG, ' ', C_TLS13_CIPHERS},
599 {"tlsauthtype", ARG_STRG, ' ', C_TLSAUTHTYPE},
600 {"tlspassword", ARG_STRG, ' ', C_TLSPASSWORD},
601 {"tlsuser", ARG_STRG, ' ', C_TLSUSER},
602 {"tlsv1", ARG_NONE, '1', C_TLSV1},
603 {"tlsv1.0", ARG_NONE, ' ', C_TLSV1_0},
604 {"tlsv1.1", ARG_NONE, ' ', C_TLSV1_1},
605 {"tlsv1.2", ARG_NONE, ' ', C_TLSV1_2},
606 {"tlsv1.3", ARG_NONE, ' ', C_TLSV1_3},
607 {"tr-encoding", ARG_BOOL, ' ', C_TR_ENCODING},
608 {"trace", ARG_FILE, ' ', C_TRACE},
609 {"trace-ascii", ARG_FILE, ' ', C_TRACE_ASCII},
610 {"trace-config", ARG_STRG, ' ', C_TRACE_CONFIG},
611 {"trace-ids", ARG_BOOL, ' ', C_TRACE_IDS},
612 {"trace-time", ARG_BOOL, ' ', C_TRACE_TIME},
613 {"unix-socket", ARG_FILE, ' ', C_UNIX_SOCKET},
614 {"upload-file", ARG_FILE, 'T', C_UPLOAD_FILE},
615 {"url", ARG_STRG, ' ', C_URL},
616 {"url-query", ARG_STRG, ' ', C_URL_QUERY},
617 {"use-ascii", ARG_BOOL, 'B', C_USE_ASCII},
618 {"user", ARG_STRG, 'u', C_USER},
619 {"user-agent", ARG_STRG, 'A', C_USER_AGENT},
620 {"variable", ARG_STRG, ' ', C_VARIABLE},
621 {"verbose", ARG_BOOL, 'v', C_VERBOSE},
622 {"version", ARG_BOOL, 'V', C_VERSION},
623 #ifdef USE_WATT32
624 {"wdebug", ARG_BOOL, ' ', C_WDEBUG},
625 #endif
626 {"write-out", ARG_STRG, 'w', C_WRITE_OUT},
627 {"xattr", ARG_BOOL, ' ', C_XATTR},
628 };
629
630 /* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
631 * We allow ':' and '\' to be escaped by '\' so that we can use certificate
632 * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/>
633 * for details. */
634 #ifndef UNITTESTS
635 static
636 #endif
parse_cert_parameter(const char * cert_parameter,char ** certname,char ** passphrase)637 void parse_cert_parameter(const char *cert_parameter,
638 char **certname,
639 char **passphrase)
640 {
641 size_t param_length = strlen(cert_parameter);
642 size_t span;
643 const char *param_place = NULL;
644 char *certname_place = NULL;
645 *certname = NULL;
646 *passphrase = NULL;
647
648 /* most trivial assumption: cert_parameter is empty */
649 if(param_length == 0)
650 return;
651
652 /* next less trivial: cert_parameter starts 'pkcs11:' and thus
653 * looks like a RFC7512 PKCS#11 URI which can be used as-is.
654 * Also if cert_parameter contains no colon nor backslash, this
655 * means no passphrase was given and no characters escaped */
656 if(curl_strnequal(cert_parameter, "pkcs11:", 7) ||
657 !strpbrk(cert_parameter, ":\\")) {
658 *certname = strdup(cert_parameter);
659 return;
660 }
661 /* deal with escaped chars; find unescaped colon if it exists */
662 certname_place = malloc(param_length + 1);
663 if(!certname_place)
664 return;
665
666 *certname = certname_place;
667 param_place = cert_parameter;
668 while(*param_place) {
669 span = strcspn(param_place, ":\\");
670 strncpy(certname_place, param_place, span);
671 param_place += span;
672 certname_place += span;
673 /* we just ate all the non-special chars. now we're on either a special
674 * char or the end of the string. */
675 switch(*param_place) {
676 case '\0':
677 break;
678 case '\\':
679 param_place++;
680 switch(*param_place) {
681 case '\0':
682 *certname_place++ = '\\';
683 break;
684 case '\\':
685 *certname_place++ = '\\';
686 param_place++;
687 break;
688 case ':':
689 *certname_place++ = ':';
690 param_place++;
691 break;
692 default:
693 *certname_place++ = '\\';
694 *certname_place++ = *param_place;
695 param_place++;
696 break;
697 }
698 break;
699 case ':':
700 /* Since we live in a world of weirdness and confusion, the win32
701 dudes can use : when using drive letters and thus c:\file:password
702 needs to work. In order not to break compatibility, we still use : as
703 separator, but we try to detect when it is used for a file name! On
704 windows. */
705 #ifdef _WIN32
706 if((param_place == &cert_parameter[1]) &&
707 (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
708 (ISALPHA(cert_parameter[0])) ) {
709 /* colon in the second column, followed by a backslash, and the
710 first character is an alphabetic letter:
711
712 this is a drive letter colon */
713 *certname_place++ = ':';
714 param_place++;
715 break;
716 }
717 #endif
718 /* escaped colons and Windows drive letter colons were handled
719 * above; if we're still here, this is a separating colon */
720 param_place++;
721 if(*param_place) {
722 *passphrase = strdup(param_place);
723 }
724 goto done;
725 }
726 }
727 done:
728 *certname_place = '\0';
729 }
730
731 /* Replace (in-place) '%20' by '+' according to RFC1866 */
replace_url_encoded_space_by_plus(char * url)732 static size_t replace_url_encoded_space_by_plus(char *url)
733 {
734 size_t orig_len = strlen(url);
735 size_t orig_index = 0;
736 size_t new_index = 0;
737
738 while(orig_index < orig_len) {
739 if((url[orig_index] == '%') &&
740 (url[orig_index + 1] == '2') &&
741 (url[orig_index + 2] == '0')) {
742 url[new_index] = '+';
743 orig_index += 3;
744 }
745 else{
746 if(new_index != orig_index) {
747 url[new_index] = url[orig_index];
748 }
749 orig_index++;
750 }
751 new_index++;
752 }
753
754 url[new_index] = 0; /* terminate string */
755
756 return new_index; /* new size */
757 }
758
759 static void
GetFileAndPassword(char * nextarg,char ** file,char ** password)760 GetFileAndPassword(char *nextarg, char **file, char **password)
761 {
762 char *certname, *passphrase;
763 if(nextarg) {
764 parse_cert_parameter(nextarg, &certname, &passphrase);
765 Curl_safefree(*file);
766 *file = certname;
767 if(passphrase) {
768 Curl_safefree(*password);
769 *password = passphrase;
770 }
771 }
772 }
773
774 /* Get a size parameter for '--limit-rate' or '--max-filesize'.
775 * We support a 'G', 'M' or 'K' suffix too.
776 */
GetSizeParameter(struct GlobalConfig * global,const char * arg,const char * which,curl_off_t * value_out)777 static ParameterError GetSizeParameter(struct GlobalConfig *global,
778 const char *arg,
779 const char *which,
780 curl_off_t *value_out)
781 {
782 char *unit;
783 curl_off_t value;
784
785 if(curlx_strtoofft(arg, &unit, 10, &value)) {
786 warnf(global, "invalid number specified for %s", which);
787 return PARAM_BAD_USE;
788 }
789
790 if(!*unit)
791 unit = (char *)"b";
792 else if(strlen(unit) > 1)
793 unit = (char *)"w"; /* unsupported */
794
795 switch(*unit) {
796 case 'G':
797 case 'g':
798 if(value > (CURL_OFF_T_MAX / (1024*1024*1024)))
799 return PARAM_NUMBER_TOO_LARGE;
800 value *= 1024*1024*1024;
801 break;
802 case 'M':
803 case 'm':
804 if(value > (CURL_OFF_T_MAX / (1024*1024)))
805 return PARAM_NUMBER_TOO_LARGE;
806 value *= 1024*1024;
807 break;
808 case 'K':
809 case 'k':
810 if(value > (CURL_OFF_T_MAX / 1024))
811 return PARAM_NUMBER_TOO_LARGE;
812 value *= 1024;
813 break;
814 case 'b':
815 case 'B':
816 /* for plain bytes, leave as-is */
817 break;
818 default:
819 warnf(global, "unsupported %s unit. Use G, M, K or B", which);
820 return PARAM_BAD_USE;
821 }
822 *value_out = value;
823 return PARAM_OK;
824 }
825
826 #ifdef HAVE_WRITABLE_ARGV
cleanarg(argv_item_t str)827 static void cleanarg(argv_item_t str)
828 {
829 /* now that getstr has copied the contents of nextarg, wipe the next
830 * argument out so that the username:password isn't displayed in the
831 * system process list */
832 if(str) {
833 size_t len = strlen(str);
834 memset(str, ' ', len);
835 }
836 }
837 #else
838 #define cleanarg(x)
839 #endif
840
841 /* --data-urlencode */
data_urlencode(struct GlobalConfig * global,char * nextarg,char ** postp,size_t * lenp)842 static ParameterError data_urlencode(struct GlobalConfig *global,
843 char *nextarg,
844 char **postp,
845 size_t *lenp)
846 {
847 /* [name]=[content], we encode the content part only
848 * [name]@[file name]
849 *
850 * Case 2: we first load the file using that name and then encode
851 * the content.
852 */
853 ParameterError err;
854 const char *p = strchr(nextarg, '=');
855 size_t nlen;
856 char is_file;
857 char *postdata = NULL;
858 size_t size = 0;
859 if(!p)
860 /* there was no '=' letter, check for a '@' instead */
861 p = strchr(nextarg, '@');
862 if(p) {
863 nlen = p - nextarg; /* length of the name part */
864 is_file = *p++; /* pass the separator */
865 }
866 else {
867 /* neither @ nor =, so no name and it isn't a file */
868 nlen = 0;
869 is_file = 0;
870 p = nextarg;
871 }
872 if('@' == is_file) {
873 FILE *file;
874 /* a '@' letter, it means that a file name or - (stdin) follows */
875 if(!strcmp("-", p)) {
876 file = stdin;
877 set_binmode(stdin);
878 }
879 else {
880 file = fopen(p, "rb");
881 if(!file) {
882 errorf(global, "Failed to open %s", p);
883 return PARAM_READ_ERROR;
884 }
885 }
886
887 err = file2memory(&postdata, &size, file);
888
889 if(file && (file != stdin))
890 fclose(file);
891 if(err)
892 return err;
893 }
894 else {
895 err = getstr(&postdata, p, ALLOW_BLANK);
896 if(err)
897 goto error;
898 size = strlen(postdata);
899 }
900
901 if(!postdata) {
902 /* no data from the file, point to a zero byte string to make this
903 get sent as a POST anyway */
904 postdata = strdup("");
905 if(!postdata)
906 return PARAM_NO_MEM;
907 size = 0;
908 }
909 else {
910 char *enc = curl_easy_escape(NULL, postdata, (int)size);
911 Curl_safefree(postdata); /* no matter if it worked or not */
912 if(enc) {
913 char *n;
914 replace_url_encoded_space_by_plus(enc);
915 if(nlen > 0) { /* only append '=' if we have a name */
916 n = aprintf("%.*s=%s", (int)nlen, nextarg, enc);
917 curl_free(enc);
918 if(!n)
919 return PARAM_NO_MEM;
920 }
921 else
922 n = enc;
923
924 size = strlen(n);
925 postdata = n;
926 }
927 else
928 return PARAM_NO_MEM;
929 }
930 *postp = postdata;
931 *lenp = size;
932 return PARAM_OK;
933 error:
934 return err;
935 }
936
sethttpver(struct GlobalConfig * global,struct OperationConfig * config,long httpversion)937 static void sethttpver(struct GlobalConfig *global,
938 struct OperationConfig *config,
939 long httpversion)
940 {
941 if(config->httpversion &&
942 (config->httpversion != httpversion))
943 warnf(global, "Overrides previous HTTP version option");
944
945 config->httpversion = httpversion;
946 }
947
set_trace_config(struct GlobalConfig * global,const char * config)948 static CURLcode set_trace_config(struct GlobalConfig *global,
949 const char *config)
950 {
951 CURLcode result = CURLE_OK;
952 char *token, *tmp, *name;
953 bool toggle;
954
955 tmp = strdup(config);
956 if(!tmp)
957 return CURLE_OUT_OF_MEMORY;
958
959 /* Allow strtok() here since this isn't used threaded */
960 /* !checksrc! disable BANNEDFUNC 2 */
961 token = strtok(tmp, ", ");
962 while(token) {
963 switch(*token) {
964 case '-':
965 toggle = FALSE;
966 name = token + 1;
967 break;
968 case '+':
969 toggle = TRUE;
970 name = token + 1;
971 break;
972 default:
973 toggle = TRUE;
974 name = token;
975 break;
976 }
977
978 if(strcasecompare(name, "all")) {
979 global->traceids = toggle;
980 global->tracetime = toggle;
981 result = curl_global_trace(token);
982 if(result)
983 goto out;
984 }
985 else if(strcasecompare(name, "ids")) {
986 global->traceids = toggle;
987 }
988 else if(strcasecompare(name, "time")) {
989 global->tracetime = toggle;
990 }
991 else {
992 result = curl_global_trace(token);
993 if(result)
994 goto out;
995 }
996 token = strtok(NULL, ", ");
997 }
998 out:
999 free(tmp);
1000 return result;
1001 }
1002
findarg(const void * a,const void * b)1003 static int findarg(const void *a, const void *b)
1004 {
1005 const struct LongShort *aa = a;
1006 const struct LongShort *bb = b;
1007 return strcmp(aa->lname, bb->lname);
1008 }
1009
single(char letter)1010 static const struct LongShort *single(char letter)
1011 {
1012 static const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */
1013 static bool singles_done = FALSE;
1014 if((letter >= 127) || (letter <= ' '))
1015 return NULL;
1016
1017 if(!singles_done) {
1018 unsigned int j;
1019 for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
1020 if(aliases[j].letter != ' ') {
1021 unsigned char l = (unsigned char)aliases[j].letter;
1022 singles[l - ' '] = &aliases[j];
1023 }
1024 }
1025 singles_done = TRUE;
1026 }
1027 return singles[letter - ' '];
1028 }
1029
1030 #define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
url_query(char * nextarg,struct GlobalConfig * global,struct OperationConfig * config)1031 static ParameterError url_query(char *nextarg,
1032 struct GlobalConfig *global,
1033 struct OperationConfig *config)
1034 {
1035 size_t size = 0;
1036 ParameterError err = PARAM_OK;
1037 char *query;
1038 struct curlx_dynbuf dyn;
1039 curlx_dyn_init(&dyn, MAX_QUERY_LEN);
1040
1041 if(*nextarg == '+') {
1042 /* use without encoding */
1043 query = strdup(&nextarg[1]);
1044 if(!query)
1045 err = PARAM_NO_MEM;
1046 }
1047 else
1048 err = data_urlencode(global, nextarg, &query, &size);
1049
1050 if(!err) {
1051 if(config->query) {
1052 CURLcode result = curlx_dyn_addf(&dyn, "%s&%s", config->query, query);
1053 free(query);
1054 if(result)
1055 err = PARAM_NO_MEM;
1056 else {
1057 free(config->query);
1058 config->query = curlx_dyn_ptr(&dyn);
1059 }
1060 }
1061 else
1062 config->query = query;
1063 }
1064 return err;
1065 }
1066
set_data(cmdline_t cmd,char * nextarg,struct GlobalConfig * global,struct OperationConfig * config)1067 static ParameterError set_data(cmdline_t cmd,
1068 char *nextarg,
1069 struct GlobalConfig *global,
1070 struct OperationConfig *config)
1071 {
1072 char *postdata = NULL;
1073 FILE *file;
1074 size_t size = 0;
1075 ParameterError err = PARAM_OK;
1076
1077 if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */
1078 err = data_urlencode(global, nextarg, &postdata, &size);
1079 if(err)
1080 return err;
1081 }
1082 else if('@' == *nextarg && (cmd != C_DATA_RAW)) {
1083 /* the data begins with a '@' letter, it means that a file name
1084 or - (stdin) follows */
1085 nextarg++; /* pass the @ */
1086
1087 if(!strcmp("-", nextarg)) {
1088 file = stdin;
1089 if(cmd == C_DATA_BINARY) /* forced data-binary */
1090 set_binmode(stdin);
1091 }
1092 else {
1093 file = fopen(nextarg, "rb");
1094 if(!file) {
1095 errorf(global, "Failed to open %s", nextarg);
1096 return PARAM_READ_ERROR;
1097 }
1098 }
1099
1100 if((cmd == C_DATA_BINARY) || /* --data-binary */
1101 (cmd == C_JSON) /* --json */)
1102 /* forced binary */
1103 err = file2memory(&postdata, &size, file);
1104 else {
1105 err = file2string(&postdata, file);
1106 if(postdata)
1107 size = strlen(postdata);
1108 }
1109
1110 if(file && (file != stdin))
1111 fclose(file);
1112 if(err)
1113 return err;
1114
1115 if(!postdata) {
1116 /* no data from the file, point to a zero byte string to make this
1117 get sent as a POST anyway */
1118 postdata = strdup("");
1119 if(!postdata)
1120 return PARAM_NO_MEM;
1121 }
1122 }
1123 else {
1124 err = getstr(&postdata, nextarg, ALLOW_BLANK);
1125 if(err)
1126 return err;
1127 size = strlen(postdata);
1128 }
1129 if(cmd == C_JSON)
1130 config->jsoned = TRUE;
1131
1132 if(curlx_dyn_len(&config->postdata)) {
1133 /* skip separator append for --json */
1134 if(!err && (cmd != C_JSON) &&
1135 curlx_dyn_addn(&config->postdata, "&", 1))
1136 err = PARAM_NO_MEM;
1137 }
1138
1139 if(!err && curlx_dyn_addn(&config->postdata, postdata, size))
1140 err = PARAM_NO_MEM;
1141
1142 Curl_safefree(postdata);
1143
1144 config->postfields = curlx_dyn_ptr(&config->postdata);
1145 return err;
1146 }
1147
set_rate(struct GlobalConfig * global,char * nextarg)1148 static ParameterError set_rate(struct GlobalConfig *global,
1149 char *nextarg)
1150 {
1151 /* --rate */
1152 /* support a few different suffixes, extract the suffix first, then
1153 get the number and convert to per hour.
1154 /s == per second
1155 /m == per minute
1156 /h == per hour (default)
1157 /d == per day (24 hours)
1158 */
1159 ParameterError err = PARAM_OK;
1160 char *div = strchr(nextarg, '/');
1161 char number[26];
1162 long denominator;
1163 long numerator = 60*60*1000; /* default per hour */
1164 size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg);
1165 if(numlen > sizeof(number) -1)
1166 return PARAM_NUMBER_TOO_LARGE;
1167
1168 strncpy(number, nextarg, numlen);
1169 number[numlen] = 0;
1170 err = str2unum(&denominator, number);
1171 if(err)
1172 return err;
1173
1174 if(denominator < 1)
1175 return PARAM_BAD_USE;
1176
1177 if(div) {
1178 char unit = div[1];
1179 switch(unit) {
1180 case 's': /* per second */
1181 numerator = 1000;
1182 break;
1183 case 'm': /* per minute */
1184 numerator = 60*1000;
1185 break;
1186 case 'h': /* per hour */
1187 break;
1188 case 'd': /* per day */
1189 numerator = 24*60*60*1000;
1190 break;
1191 default:
1192 errorf(global, "unsupported --rate unit");
1193 err = PARAM_BAD_USE;
1194 break;
1195 }
1196 }
1197
1198 if(err)
1199 ;
1200 else if(denominator > numerator)
1201 err = PARAM_NUMBER_TOO_LARGE;
1202 else
1203 global->ms_per_transfer = numerator/denominator;
1204
1205 return err;
1206 }
1207
1208
getparameter(const char * flag,char * nextarg,argv_item_t cleararg,bool * usedarg,struct GlobalConfig * global,struct OperationConfig * config)1209 ParameterError getparameter(const char *flag, /* f or -long-flag */
1210 char *nextarg, /* NULL if unset */
1211 argv_item_t cleararg,
1212 bool *usedarg, /* set to TRUE if the arg
1213 has been used */
1214 struct GlobalConfig *global,
1215 struct OperationConfig *config)
1216 {
1217 int rc;
1218 const char *parse = NULL;
1219 time_t now;
1220 bool longopt = FALSE;
1221 bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
1222 ParameterError err = PARAM_OK;
1223 bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
1224 by using --OPTION or --no-OPTION */
1225 bool nextalloc = FALSE; /* if nextarg is allocated */
1226 struct getout *url;
1227 static const char *redir_protos[] = {
1228 "http",
1229 "https",
1230 "ftp",
1231 "ftps",
1232 NULL
1233 };
1234 const struct LongShort *a = NULL;
1235 curl_off_t value;
1236 #ifdef HAVE_WRITABLE_ARGV
1237 argv_item_t clearthis = NULL;
1238 #else
1239 (void)cleararg;
1240 #endif
1241
1242 *usedarg = FALSE; /* default is that we don't use the arg */
1243
1244 if(('-' != flag[0]) || ('-' == flag[1])) {
1245 /* this should be a long name */
1246 const char *word = ('-' == flag[0]) ? flag + 2 : flag;
1247 bool noflagged = FALSE;
1248 bool expand = FALSE;
1249 struct LongShort key;
1250
1251 if(!strncmp(word, "no-", 3)) {
1252 /* disable this option but ignore the "no-" part when looking for it */
1253 word += 3;
1254 toggle = FALSE;
1255 noflagged = TRUE;
1256 }
1257 else if(!strncmp(word, "expand-", 7)) {
1258 /* variable expansions is to be done on the argument */
1259 word += 7;
1260 expand = TRUE;
1261 }
1262 key.lname = word;
1263
1264 a = bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]),
1265 sizeof(aliases[0]), findarg);
1266 if(a) {
1267 longopt = TRUE;
1268 }
1269 else {
1270 err = PARAM_OPTION_UNKNOWN;
1271 goto error;
1272 }
1273 if(noflagged && (a->desc != ARG_BOOL)) {
1274 /* --no- prefixed an option that isn't boolean! */
1275 err = PARAM_NO_NOT_BOOLEAN;
1276 goto error;
1277 }
1278 else if(expand && nextarg) {
1279 struct curlx_dynbuf nbuf;
1280 bool replaced;
1281
1282 if((a->desc != ARG_STRG) &&
1283 (a->desc != ARG_FILE)) {
1284 /* --expand on an option that isn't a string or a filename */
1285 err = PARAM_EXPAND_ERROR;
1286 goto error;
1287 }
1288 err = varexpand(global, nextarg, &nbuf, &replaced);
1289 if(err) {
1290 curlx_dyn_free(&nbuf);
1291 goto error;
1292 }
1293 if(replaced) {
1294 nextarg = curlx_dyn_ptr(&nbuf);
1295 nextalloc = TRUE;
1296 }
1297 }
1298 }
1299 else {
1300 flag++; /* prefixed with one dash, pass it */
1301 parse = flag;
1302 }
1303
1304 do {
1305 /* we can loop here if we have multiple single-letters */
1306 char letter;
1307 cmdline_t cmd;
1308
1309 if(!longopt && !a) {
1310 a = single(*parse);
1311 if(!a) {
1312 err = PARAM_OPTION_UNKNOWN;
1313 break;
1314 }
1315 }
1316 letter = a->letter;
1317 cmd = a->cmd;
1318 if(a->desc >= ARG_STRG) {
1319 /* this option requires an extra parameter */
1320 if(!longopt && parse[1]) {
1321 nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
1322 singleopt = TRUE; /* don't loop anymore after this */
1323 }
1324 else if(!nextarg) {
1325 err = PARAM_REQUIRES_PARAMETER;
1326 break;
1327 }
1328 else {
1329 #ifdef HAVE_WRITABLE_ARGV
1330 clearthis = cleararg;
1331 #endif
1332 *usedarg = TRUE; /* mark it as used */
1333 }
1334
1335 if((a->desc == ARG_FILE) &&
1336 (nextarg[0] == '-') && nextarg[1]) {
1337 /* if the file name looks like a command line option */
1338 warnf(global, "The file name argument '%s' looks like a flag.",
1339 nextarg);
1340 }
1341 else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
1342 warnf(global, "The argument '%s' starts with a unicode quote where "
1343 "maybe an ASCII \" was intended?",
1344 nextarg);
1345 }
1346 }
1347 else if((a->desc == ARG_NONE) && !toggle) {
1348 err = PARAM_NO_PREFIX;
1349 break;
1350 }
1351
1352 if(!nextarg)
1353 /* this is a precaution mostly to please scan-build, as all arguments
1354 that use nextarg should be marked as such and they will check that
1355 nextarg is set before continuing, but code analyzers are not always
1356 that aware of that state */
1357 nextarg = (char *)"";
1358
1359 switch(cmd) {
1360 case C_RANDOM_FILE: /* --random-file */
1361 case C_EGD_FILE: /* --egd-file */
1362 case C_NTLM_WB: /* --ntlm-wb */
1363 warnf(global, "--%s is deprecated and has no function anymore",
1364 a->lname);
1365 break;
1366 case C_DNS_IPV4_ADDR: /* --dns-ipv4-addr */
1367 if(!curlinfo->ares_num) /* c-ares is needed for this */
1368 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1369 else
1370 /* addr in dot notation */
1371 err = getstr(&config->dns_ipv4_addr, nextarg, DENY_BLANK);
1372 break;
1373 case C_DNS_IPV6_ADDR: /* --dns-ipv6-addr */
1374 if(!curlinfo->ares_num) /* c-ares is needed for this */
1375 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1376 else
1377 /* addr in dot notation */
1378 err = getstr(&config->dns_ipv6_addr, nextarg, DENY_BLANK);
1379 break;
1380 case C_OAUTH2_BEARER: /* --oauth2-bearer */
1381 err = getstr(&config->oauth_bearer, nextarg, DENY_BLANK);
1382 if(!err) {
1383 cleanarg(clearthis);
1384 config->authtype |= CURLAUTH_BEARER;
1385 }
1386 break;
1387 case C_CONNECT_TIMEOUT: /* --connect-timeout */
1388 err = secs2ms(&config->connecttimeout_ms, nextarg);
1389 break;
1390 case C_DOH_URL: /* --doh-url */
1391 err = getstr(&config->doh_url, nextarg, ALLOW_BLANK);
1392 if(!err && config->doh_url && !config->doh_url[0])
1393 /* if given a blank string, make it NULL again */
1394 Curl_safefree(config->doh_url);
1395 break;
1396 case C_CIPHERS: /* -- ciphers */
1397 err = getstr(&config->cipher_list, nextarg, DENY_BLANK);
1398 break;
1399 case C_DNS_INTERFACE: /* --dns-interface */
1400 if(!curlinfo->ares_num) /* c-ares is needed for this */
1401 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1402 else
1403 /* interface name */
1404 err = getstr(&config->dns_interface, nextarg, DENY_BLANK);
1405 break;
1406 case C_DISABLE_EPSV: /* --disable-epsv */
1407 config->disable_epsv = toggle;
1408 break;
1409 case C_DISALLOW_USERNAME_IN_URL: /* --disallow-username-in-url */
1410 config->disallow_username_in_url = toggle;
1411 break;
1412 case C_EPSV: /* --epsv */
1413 config->disable_epsv = (!toggle)?TRUE:FALSE;
1414 break;
1415 case C_DNS_SERVERS: /* --dns-servers */
1416 if(!curlinfo->ares_num) /* c-ares is needed for this */
1417 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1418 else
1419 /* IP addrs of DNS servers */
1420 err = getstr(&config->dns_servers, nextarg, DENY_BLANK);
1421 break;
1422 case C_TRACE: /* --trace */
1423 err = getstr(&global->trace_dump, nextarg, DENY_BLANK);
1424 if(!err) {
1425 if(global->tracetype && (global->tracetype != TRACE_BIN))
1426 warnf(global, "--trace overrides an earlier trace/verbose option");
1427 global->tracetype = TRACE_BIN;
1428 }
1429 break;
1430 case C_NPN: /* --npn */
1431 warnf(global, "--npn is no longer supported");
1432 break;
1433 case C_TRACE_ASCII: /* --trace-ascii */
1434 err = getstr(&global->trace_dump, nextarg, DENY_BLANK);
1435 if(!err) {
1436 if(global->tracetype && (global->tracetype != TRACE_ASCII))
1437 warnf(global,
1438 "--trace-ascii overrides an earlier trace/verbose option");
1439 global->tracetype = TRACE_ASCII;
1440 }
1441 break;
1442 case C_ALPN: /* --alpn */
1443 config->noalpn = (!toggle)?TRUE:FALSE;
1444 break;
1445 case C_LIMIT_RATE: /* --limit-rate */
1446 err = GetSizeParameter(global, nextarg, "rate", &value);
1447 if(!err) {
1448 config->recvpersecond = value;
1449 config->sendpersecond = value;
1450 }
1451 break;
1452 case C_RATE:
1453 err = set_rate(global, nextarg);
1454 break;
1455 case C_COMPRESSED: /* --compressed */
1456 if(toggle && !(feature_libz || feature_brotli || feature_zstd))
1457 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1458 else
1459 config->encoding = toggle;
1460 break;
1461 case C_TR_ENCODING: /* --tr-encoding */
1462 config->tr_encoding = toggle;
1463 break;
1464 case C_DIGEST: /* --digest */
1465 if(toggle)
1466 config->authtype |= CURLAUTH_DIGEST;
1467 else
1468 config->authtype &= ~CURLAUTH_DIGEST;
1469 break;
1470 case C_NEGOTIATE: /* --negotiate */
1471 if(!toggle)
1472 config->authtype &= ~CURLAUTH_NEGOTIATE;
1473 else if(feature_spnego)
1474 config->authtype |= CURLAUTH_NEGOTIATE;
1475 else
1476 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1477 break;
1478 case C_NTLM: /* --ntlm */
1479 if(!toggle)
1480 config->authtype &= ~CURLAUTH_NTLM;
1481 else if(feature_ntlm)
1482 config->authtype |= CURLAUTH_NTLM;
1483 else
1484 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1485 break;
1486 case C_BASIC: /* --basic */
1487 if(toggle)
1488 config->authtype |= CURLAUTH_BASIC;
1489 else
1490 config->authtype &= ~CURLAUTH_BASIC;
1491 break;
1492 case C_ANYAUTH: /* --anyauth */
1493 if(toggle)
1494 config->authtype = CURLAUTH_ANY;
1495 /* --no-anyauth simply doesn't touch it */
1496 break;
1497 #ifdef USE_WATT32
1498 case C_WDEBUG: /* --wdebug */
1499 dbug_init();
1500 break;
1501 #endif
1502 case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */
1503 config->ftp_create_dirs = toggle;
1504 break;
1505 case C_CREATE_DIRS: /* --create-dirs */
1506 config->create_dirs = toggle;
1507 break;
1508 case C_CREATE_FILE_MODE: /* --create-file-mode */
1509 err = oct2nummax(&config->create_file_mode, nextarg, 0777);
1510 break;
1511 case C_MAX_REDIRS: /* --max-redirs */
1512 /* specified max no of redirects (http(s)), this accepts -1 as a
1513 special condition */
1514 err = str2num(&config->maxredirs, nextarg);
1515 if(!err && (config->maxredirs < -1))
1516 err = PARAM_BAD_NUMERIC;
1517 break;
1518 case C_IPFS_GATEWAY: /* --ipfs-gateway */
1519 err = getstr(&config->ipfs_gateway, nextarg, DENY_BLANK);
1520 break;
1521 case C_PROXY_NTLM: /* --proxy-ntlm */
1522 if(!feature_ntlm)
1523 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1524 else
1525 config->proxyntlm = toggle;
1526 break;
1527 case C_CRLF: /* --crlf */
1528 /* LF -> CRLF conversion? */
1529 config->crlf = toggle;
1530 break;
1531 case C_AWS_SIGV4: /* --aws-sigv4 */
1532 config->authtype |= CURLAUTH_AWS_SIGV4;
1533 err = getstr(&config->aws_sigv4, nextarg, DENY_BLANK);
1534 break;
1535 case C_STDERR: /* --stderr */
1536 tool_set_stderr_file(global, nextarg);
1537 break;
1538 case C_INTERFACE: /* --interface */
1539 /* interface */
1540 err = getstr(&config->iface, nextarg, DENY_BLANK);
1541 break;
1542 case C_KRB: /* --krb */
1543 /* kerberos level string */
1544 if(!feature_spnego)
1545 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1546 else
1547 err = getstr(&config->krblevel, nextarg, DENY_BLANK);
1548 break;
1549 case C_HAPROXY_PROTOCOL: /* --haproxy-protocol */
1550 config->haproxy_protocol = toggle;
1551 break;
1552 case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */
1553 err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK);
1554 break;
1555 case C_MAX_FILESIZE: /* --max-filesize */
1556 err = GetSizeParameter(global, nextarg, "max-filesize", &value);
1557 if(!err)
1558 config->max_filesize = value;
1559 break;
1560 case C_DISABLE_EPRT: /* --disable-eprt */
1561 config->disable_eprt = toggle;
1562 break;
1563 case C_EPRT: /* --eprt */
1564 config->disable_eprt = (!toggle)?TRUE:FALSE;
1565 break;
1566 case C_XATTR: /* --xattr */
1567 config->xattr = toggle;
1568 break;
1569 case C_URL: /* --url */
1570 if(!config->url_get)
1571 config->url_get = config->url_list;
1572
1573 if(config->url_get) {
1574 /* there's a node here, if it already is filled-in continue to find
1575 an "empty" node */
1576 while(config->url_get && (config->url_get->flags & GETOUT_URL))
1577 config->url_get = config->url_get->next;
1578 }
1579
1580 /* now there might or might not be an available node to fill in! */
1581
1582 if(config->url_get)
1583 /* existing node */
1584 url = config->url_get;
1585 else
1586 /* there was no free node, create one! */
1587 config->url_get = url = new_getout(config);
1588
1589 if(!url)
1590 err = PARAM_NO_MEM;
1591 else {
1592 /* fill in the URL */
1593 err = getstr(&url->url, nextarg, DENY_BLANK);
1594 url->flags |= GETOUT_URL;
1595 }
1596 break;
1597 case C_FTP_SSL: /* --ftp-ssl */
1598 case C_SSL: /* --ssl */
1599 if(toggle && !feature_ssl)
1600 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1601 else {
1602 config->ftp_ssl = toggle;
1603 if(config->ftp_ssl)
1604 warnf(global,
1605 "--%s is an insecure option, consider --ssl-reqd instead",
1606 a->lname);
1607 }
1608 break;
1609 case C_FTP_PASV: /* --ftp-pasv */
1610 Curl_safefree(config->ftpport);
1611 break;
1612 case C_SOCKS5: /* --socks5 */
1613 /* socks5 proxy to use, and resolves the name locally and passes on the
1614 resolved address */
1615 err = getstr(&config->proxy, nextarg, DENY_BLANK);
1616 config->proxyver = CURLPROXY_SOCKS5;
1617 break;
1618 case C_SOCKS4: /* --socks4 */
1619 err = getstr(&config->proxy, nextarg, DENY_BLANK);
1620 config->proxyver = CURLPROXY_SOCKS4;
1621 break;
1622 case C_SOCKS4A: /* --socks4a */
1623 err = getstr(&config->proxy, nextarg, DENY_BLANK);
1624 config->proxyver = CURLPROXY_SOCKS4A;
1625 break;
1626 case C_SOCKS5_HOSTNAME: /* --socks5-hostname */
1627 err = getstr(&config->proxy, nextarg, DENY_BLANK);
1628 config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
1629 break;
1630 case C_TCP_NODELAY: /* --tcp-nodelay */
1631 config->tcp_nodelay = toggle;
1632 break;
1633 case C_PROXY_DIGEST: /* --proxy-digest */
1634 config->proxydigest = toggle;
1635 break;
1636 case C_PROXY_BASIC: /* --proxy-basic */
1637 config->proxybasic = toggle;
1638 break;
1639 case C_RETRY: /* --retry */
1640 err = str2unum(&config->req_retry, nextarg);
1641 break;
1642 case C_RETRY_CONNREFUSED: /* --retry-connrefused */
1643 config->retry_connrefused = toggle;
1644 break;
1645 case C_RETRY_DELAY: /* --retry-delay */
1646 err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000);
1647 break;
1648 case C_RETRY_MAX_TIME: /* --retry-max-time */
1649 err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000);
1650 break;
1651 case C_RETRY_ALL_ERRORS: /* --retry-all-errors */
1652 config->retry_all_errors = toggle;
1653 break;
1654 case C_PROXY_NEGOTIATE: /* --proxy-negotiate */
1655 if(!feature_spnego)
1656 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1657 else
1658 config->proxynegotiate = toggle;
1659 break;
1660 case C_FORM_ESCAPE: /* --form-escape */
1661 config->mime_options &= ~CURLMIMEOPT_FORMESCAPE;
1662 if(toggle)
1663 config->mime_options |= CURLMIMEOPT_FORMESCAPE;
1664 break;
1665 case C_FTP_ACCOUNT: /* --ftp-account */
1666 err = getstr(&config->ftp_account, nextarg, DENY_BLANK);
1667 break;
1668 case C_PROXY_ANYAUTH: /* --proxy-anyauth */
1669 config->proxyanyauth = toggle;
1670 break;
1671 case C_TRACE_TIME: /* --trace-time */
1672 global->tracetime = toggle;
1673 break;
1674 case C_IGNORE_CONTENT_LENGTH: /* --ignore-content-length */
1675 config->ignorecl = toggle;
1676 break;
1677 case C_FTP_SKIP_PASV_IP: /* --ftp-skip-pasv-ip */
1678 config->ftp_skip_ip = toggle;
1679 break;
1680 case C_FTP_METHOD: /* --ftp-method */
1681 config->ftp_filemethod = ftpfilemethod(config, nextarg);
1682 break;
1683 case C_LOCAL_PORT: { /* --local-port */
1684 /* 16bit base 10 is 5 digits, but we allow 6 so that this catches
1685 overflows, not just truncates */
1686 char lrange[7]="";
1687 char *p = nextarg;
1688 while(ISDIGIT(*p))
1689 p++;
1690 if(*p) {
1691 /* if there's anything more than a plain decimal number */
1692 rc = sscanf(p, " - %6s", lrange);
1693 *p = 0; /* null-terminate to make str2unum() work below */
1694 }
1695 else
1696 rc = 0;
1697
1698 err = str2unum(&config->localport, nextarg);
1699 if(err || (config->localport > 65535)) {
1700 err = PARAM_BAD_USE;
1701 break;
1702 }
1703 if(!rc)
1704 config->localportrange = 1; /* default number of ports to try */
1705 else {
1706 err = str2unum(&config->localportrange, lrange);
1707 if(err || (config->localportrange > 65535))
1708 err = PARAM_BAD_USE;
1709 else {
1710 config->localportrange -= (config->localport-1);
1711 if(config->localportrange < 1)
1712 err = PARAM_BAD_USE;
1713 }
1714 }
1715 break;
1716 }
1717 case C_FTP_ALTERNATIVE_TO_USER: /* --ftp-alternative-to-user */
1718 err = getstr(&config->ftp_alternative_to_user, nextarg, DENY_BLANK);
1719 break;
1720 case C_FTP_SSL_REQD: /* --ftp-ssl-reqd */
1721 case C_SSL_REQD: /* --ssl-reqd */
1722 if(toggle && !feature_ssl) {
1723 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1724 break;
1725 }
1726 config->ftp_ssl_reqd = toggle;
1727 break;
1728 case C_SESSIONID: /* --sessionid */
1729 config->disable_sessionid = (!toggle)?TRUE:FALSE;
1730 break;
1731 case C_FTP_SSL_CONTROL: /* --ftp-ssl-control */
1732 if(toggle && !feature_ssl)
1733 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1734 else
1735 config->ftp_ssl_control = toggle;
1736 break;
1737 case C_FTP_SSL_CCC: /* --ftp-ssl-ccc */
1738 config->ftp_ssl_ccc = toggle;
1739 if(!config->ftp_ssl_ccc_mode)
1740 config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
1741 break;
1742 case C_FTP_SSL_CCC_MODE: /* --ftp-ssl-ccc-mode */
1743 config->ftp_ssl_ccc = TRUE;
1744 config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
1745 break;
1746 case C_LIBCURL: /* --libcurl */
1747 #ifdef CURL_DISABLE_LIBCURL_OPTION
1748 warnf(global,
1749 "--libcurl option was disabled at build-time");
1750 err = PARAM_OPTION_UNKNOWN;
1751 #else
1752 err = getstr(&global->libcurl, nextarg, DENY_BLANK);
1753 #endif
1754 break;
1755 case C_RAW: /* --raw */
1756 config->raw = toggle;
1757 break;
1758 case C_KEEPALIVE: /* --keepalive */
1759 config->nokeepalive = (!toggle)?TRUE:FALSE;
1760 break;
1761 case C_KEEPALIVE_TIME: /* --keepalive-time */
1762 err = str2unum(&config->alivetime, nextarg);
1763 break;
1764 case C_POST301: /* --post301 */
1765 config->post301 = toggle;
1766 break;
1767 case C_POST302: /* --post302 */
1768 config->post302 = toggle;
1769 break;
1770 case C_POST303: /* --post303 */
1771 config->post303 = toggle;
1772 break;
1773 case C_NOPROXY: /* --noproxy */
1774 /* This specifies the noproxy list */
1775 err = getstr(&config->noproxy, nextarg, ALLOW_BLANK);
1776 break;
1777 case C_SOCKS5_GSSAPI_NEC: /* --socks5-gssapi-nec */
1778 config->socks5_gssapi_nec = toggle;
1779 break;
1780 case C_PROXY1_0: /* --proxy1.0 */
1781 /* http 1.0 proxy */
1782 err = getstr(&config->proxy, nextarg, DENY_BLANK);
1783 config->proxyver = CURLPROXY_HTTP_1_0;
1784 break;
1785 case C_TFTP_BLKSIZE: /* --tftp-blksize */
1786 err = str2unum(&config->tftp_blksize, nextarg);
1787 break;
1788 case C_MAIL_FROM: /* --mail-from */
1789 err = getstr(&config->mail_from, nextarg, DENY_BLANK);
1790 break;
1791 case C_MAIL_RCPT: /* --mail-rcpt */
1792 /* append receiver to a list */
1793 err = add2list(&config->mail_rcpt, nextarg);
1794 break;
1795 case C_FTP_PRET: /* --ftp-pret */
1796 config->ftp_pret = toggle;
1797 break;
1798 case C_PROTO: /* --proto */
1799 config->proto_present = TRUE;
1800 err = proto2num(config, built_in_protos, &config->proto_str, nextarg);
1801 break;
1802 case C_PROTO_REDIR: /* --proto-redir */
1803 config->proto_redir_present = TRUE;
1804 if(proto2num(config, redir_protos, &config->proto_redir_str,
1805 nextarg))
1806 err = PARAM_BAD_USE;
1807 break;
1808 case C_RESOLVE: /* --resolve */
1809 err = add2list(&config->resolve, nextarg);
1810 break;
1811 case C_DELEGATION: /* --delegation */
1812 config->gssapi_delegation = delegation(config, nextarg);
1813 break;
1814 case C_MAIL_AUTH: /* --mail-auth */
1815 err = getstr(&config->mail_auth, nextarg, DENY_BLANK);
1816 break;
1817 case C_METALINK: /* --metalink */
1818 errorf(global, "--metalink is disabled");
1819 err = PARAM_BAD_USE;
1820 break;
1821 case C_SASL_AUTHZID: /* --sasl-authzid */
1822 err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK);
1823 break;
1824 case C_SASL_IR: /* --sasl-ir */
1825 config->sasl_ir = toggle;
1826 break;
1827 case C_TEST_EVENT: /* --test-event */
1828 #ifdef CURLDEBUG
1829 global->test_event_based = toggle;
1830 #else
1831 warnf(global, "--test-event is ignored unless a debug build");
1832 #endif
1833 break;
1834 case C_UNIX_SOCKET: /* --unix-socket */
1835 config->abstract_unix_socket = FALSE;
1836 err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
1837 break;
1838 case C_PATH_AS_IS: /* --path-as-is */
1839 config->path_as_is = toggle;
1840 break;
1841 case C_PROXY_SERVICE_NAME: /* --proxy-service-name */
1842 err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK);
1843 break;
1844 case C_SERVICE_NAME: /* --service-name */
1845 err = getstr(&config->service_name, nextarg, DENY_BLANK);
1846 break;
1847 case C_PROTO_DEFAULT: /* --proto-default */
1848 err = getstr(&config->proto_default, nextarg, DENY_BLANK);
1849 if(!err)
1850 err = check_protocol(config->proto_default);
1851 break;
1852 case C_EXPECT100_TIMEOUT: /* --expect100-timeout */
1853 err = secs2ms(&config->expect100timeout_ms, nextarg);
1854 break;
1855 case C_TFTP_NO_OPTIONS: /* --tftp-no-options */
1856 config->tftp_no_options = toggle;
1857 break;
1858 case C_CONNECT_TO: /* --connect-to */
1859 err = add2list(&config->connect_to, nextarg);
1860 break;
1861 case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */
1862 config->abstract_unix_socket = TRUE;
1863 err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
1864 break;
1865 case C_TLS_MAX: /* --tls-max */
1866 err = str2tls_max(&config->ssl_version_max, nextarg);
1867 break;
1868 case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */
1869 config->suppress_connect_headers = toggle;
1870 break;
1871 case C_COMPRESSED_SSH: /* --compressed-ssh */
1872 config->ssh_compression = toggle;
1873 break;
1874 case C_HAPPY_EYEBALLS_TIMEOUT_MS: /* --happy-eyeballs-timeout-ms */
1875 err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg);
1876 /* 0 is a valid value for this timeout */
1877 break;
1878 case C_TRACE_IDS: /* --trace-ids */
1879 global->traceids = toggle;
1880 break;
1881 case C_TRACE_CONFIG: /* --trace-config */
1882 if(set_trace_config(global, nextarg))
1883 err = PARAM_NO_MEM;
1884 break;
1885 case C_PROGRESS_METER: /* --progress-meter */
1886 global->noprogress = !toggle;
1887 break;
1888 case C_PROGRESS_BAR: /* --progress-bar */
1889 global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
1890 break;
1891 case C_VARIABLE: /* --Variable */
1892 err = setvariable(global, nextarg);
1893 break;
1894 case C_NEXT: /* --next */
1895 err = PARAM_NEXT_OPERATION;
1896 break;
1897 case C_HTTP1_0: /* --http1.0 */
1898 /* HTTP version 1.0 */
1899 sethttpver(global, config, CURL_HTTP_VERSION_1_0);
1900 break;
1901 case C_HTTP1_1: /* --http1.1 */
1902 /* HTTP version 1.1 */
1903 sethttpver(global, config, CURL_HTTP_VERSION_1_1);
1904 break;
1905 case C_HTTP2: /* --http2 */
1906 /* HTTP version 2.0 */
1907 if(!feature_http2)
1908 return PARAM_LIBCURL_DOESNT_SUPPORT;
1909 sethttpver(global, config, CURL_HTTP_VERSION_2_0);
1910 break;
1911 case C_HTTP2_PRIOR_KNOWLEDGE: /* --http2-prior-knowledge */
1912 /* HTTP version 2.0 over clean TCP */
1913 if(!feature_http2)
1914 return PARAM_LIBCURL_DOESNT_SUPPORT;
1915 sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
1916 break;
1917 case C_HTTP3: /* --http3: */
1918 /* Try HTTP/3, allow fallback */
1919 if(!feature_http3)
1920 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1921 else
1922 sethttpver(global, config, CURL_HTTP_VERSION_3);
1923 break;
1924 case C_HTTP3_ONLY: /* --http3-only */
1925 /* Try HTTP/3 without fallback */
1926 if(!feature_http3)
1927 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1928 else
1929 sethttpver(global, config, CURL_HTTP_VERSION_3ONLY);
1930 break;
1931 case C_HTTP0_9: /* --http0.9 */
1932 /* Allow HTTP/0.9 responses! */
1933 config->http09_allowed = toggle;
1934 break;
1935 case C_PROXY_HTTP2: /* --proxy-http2 */
1936 if(!feature_httpsproxy || !feature_http2)
1937 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1938 else
1939 config->proxyver = CURLPROXY_HTTPS2;
1940 break;
1941 case C_TLSV1: /* --tlsv1 */
1942 config->ssl_version = CURL_SSLVERSION_TLSv1;
1943 break;
1944 case C_TLSV1_0: /* --tlsv1.0 */
1945 config->ssl_version = CURL_SSLVERSION_TLSv1_0;
1946 break;
1947 case C_TLSV1_1: /* --tlsv1.1 */
1948 config->ssl_version = CURL_SSLVERSION_TLSv1_1;
1949 break;
1950 case C_TLSV1_2: /* --tlsv1.2 */
1951 config->ssl_version = CURL_SSLVERSION_TLSv1_2;
1952 break;
1953 case C_TLSV1_3: /* --tlsv1.3 */
1954 config->ssl_version = CURL_SSLVERSION_TLSv1_3;
1955 break;
1956 case C_TLS13_CIPHERS: /* --tls13-ciphers */
1957 err = getstr(&config->cipher13_list, nextarg, DENY_BLANK);
1958 break;
1959 case C_PROXY_TLS13_CIPHERS: /* --proxy-tls13-ciphers */
1960 err = getstr(&config->proxy_cipher13_list, nextarg, DENY_BLANK);
1961 break;
1962 case C_SSLV2: /* --sslv2 */
1963 warnf(global, "Ignores instruction to use SSLv2");
1964 break;
1965 case C_SSLV3: /* --sslv3 */
1966 warnf(global, "Ignores instruction to use SSLv3");
1967 break;
1968 case C_IPV4: /* --ipv4 */
1969 config->ip_version = CURL_IPRESOLVE_V4;
1970 break;
1971 case C_IPV6: /* --ipv6 */
1972 config->ip_version = CURL_IPRESOLVE_V6;
1973 break;
1974 case C_APPEND: /* --append */
1975 /* This makes the FTP sessions use APPE instead of STOR */
1976 config->ftp_append = toggle;
1977 break;
1978 case C_USER_AGENT: /* --user-agent */
1979 err = getstr(&config->useragent, nextarg, ALLOW_BLANK);
1980 break;
1981 case C_ALT_SVC: /* --alt-svc */
1982 if(!feature_altsvc)
1983 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1984 else
1985 err = getstr(&config->altsvc, nextarg, ALLOW_BLANK);
1986 break;
1987 case C_HSTS: /* --hsts */
1988 if(!feature_hsts)
1989 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1990 else
1991 err = getstr(&config->hsts, nextarg, ALLOW_BLANK);
1992 break;
1993 case C_COOKIE: /* --cookie */
1994 if(strchr(nextarg, '=')) {
1995 /* A cookie string must have a =-letter */
1996 err = add2list(&config->cookies, nextarg);
1997 break;
1998 }
1999 else {
2000 /* We have a cookie file to read from! */
2001 err = add2list(&config->cookiefiles, nextarg);
2002 }
2003 break;
2004 case C_USE_ASCII: /* --use-ascii */
2005 config->use_ascii = toggle;
2006 break;
2007 case C_COOKIE_JAR: /* --cookie-jar */
2008 err = getstr(&config->cookiejar, nextarg, DENY_BLANK);
2009 break;
2010 case C_CONTINUE_AT: /* --continue-at */
2011 /* This makes us continue an ftp transfer at given position */
2012 if(strcmp(nextarg, "-")) {
2013 err = str2offset(&config->resume_from, nextarg);
2014 config->resume_from_current = FALSE;
2015 }
2016 else {
2017 config->resume_from_current = TRUE;
2018 config->resume_from = 0;
2019 }
2020 config->use_resume = TRUE;
2021 break;
2022 case C_DATA: /* --data */
2023 case C_DATA_ASCII: /* --data-ascii */
2024 case C_DATA_BINARY: /* --data-binary */
2025 case C_DATA_URLENCODE: /* --data-urlencode */
2026 case C_JSON: /* --json */
2027 case C_DATA_RAW: /* --data-raw */
2028 err = set_data(cmd, nextarg, global, config);
2029 break;
2030 case C_URL_QUERY: /* --url-query */
2031 err = url_query(nextarg, global, config);
2032 break;
2033 case C_DUMP_HEADER: /* --dump-header */
2034 err = getstr(&config->headerfile, nextarg, DENY_BLANK);
2035 break;
2036 case C_REFERER: { /* --referer */
2037 char *ptr = strstr(nextarg, ";auto");
2038 if(ptr) {
2039 /* Automatic referer requested, this may be combined with a
2040 set initial one */
2041 config->autoreferer = TRUE;
2042 *ptr = 0; /* null-terminate here */
2043 }
2044 else
2045 config->autoreferer = FALSE;
2046 ptr = *nextarg ? nextarg : NULL;
2047 err = getstr(&config->referer, ptr, ALLOW_BLANK);
2048 }
2049 break;
2050 case C_CERT: /* --cert */
2051 cleanarg(clearthis);
2052 GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
2053 break;
2054 case C_CACERT: /* --cacert */
2055 err = getstr(&config->cacert, nextarg, DENY_BLANK);
2056 break;
2057 case C_CA_NATIVE: /* --ca-native */
2058 config->native_ca_store = toggle;
2059 break;
2060 case C_PROXY_CA_NATIVE: /* --proxy-ca-native */
2061 config->proxy_native_ca_store = toggle;
2062 break;
2063 case C_CERT_TYPE: /* --cert-type */
2064 err = getstr(&config->cert_type, nextarg, DENY_BLANK);
2065 break;
2066 case C_KEY: /* --key */
2067 err = getstr(&config->key, nextarg, DENY_BLANK);
2068 break;
2069 case C_KEY_TYPE: /* --key-type */
2070 err = getstr(&config->key_type, nextarg, DENY_BLANK);
2071 break;
2072 case C_PASS: /* --pass */
2073 err = getstr(&config->key_passwd, nextarg, DENY_BLANK);
2074 cleanarg(clearthis);
2075 break;
2076 case C_ENGINE: /* --engine */
2077 err = getstr(&config->engine, nextarg, DENY_BLANK);
2078 if(!err &&
2079 config->engine && !strcmp(config->engine, "list")) {
2080 err = PARAM_ENGINES_REQUESTED;
2081 }
2082 break;
2083 #ifndef USE_ECH
2084 case C_ECH: /* --ech, not implemented by default */
2085 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2086 break;
2087 #else
2088 case C_ECH: /* --ech */
2089 if(strlen(nextarg) > 4 && strncasecompare("pn:", nextarg, 3)) {
2090 /* a public_name */
2091 err = getstr(&config->ech_public, nextarg, DENY_BLANK);
2092 }
2093 else if(strlen(nextarg) > 5 && strncasecompare("ecl:", nextarg, 4)) {
2094 /* an ECHConfigList */
2095 if('@' != *(nextarg + 4)) {
2096 err = getstr(&config->ech_config, nextarg, DENY_BLANK);
2097 }
2098 else {
2099 /* Indirect case: @filename or @- for stdin */
2100 char *tmpcfg = NULL;
2101 FILE *file;
2102
2103 nextarg++; /* skip over '@' */
2104 if(!strcmp("-", nextarg)) {
2105 file = stdin;
2106 }
2107 else {
2108 file = fopen(nextarg, FOPEN_READTEXT);
2109 }
2110 if(!file) {
2111 warnf(global,
2112 "Couldn't read file \"%s\" "
2113 "specified for \"--ech ecl:\" option",
2114 nextarg);
2115 return PARAM_BAD_USE; /* */
2116 }
2117 err = file2string(&tmpcfg, file);
2118 if(file != stdin)
2119 fclose(file);
2120 if(err)
2121 return err;
2122 config->ech_config = aprintf("ecl:%s",tmpcfg);
2123 if(!config->ech_config)
2124 return PARAM_NO_MEM;
2125 free(tmpcfg);
2126 } /* file done */
2127 }
2128 else {
2129 /* Simple case: just a string, with a keyword */
2130 err = getstr(&config->ech, nextarg, DENY_BLANK);
2131 }
2132 break;
2133 #endif
2134 case C_CAPATH: /* --capath */
2135 err = getstr(&config->capath, nextarg, DENY_BLANK);
2136 break;
2137 case C_PUBKEY: /* --pubkey */
2138 err = getstr(&config->pubkey, nextarg, DENY_BLANK);
2139 break;
2140 case C_HOSTPUBMD5: /* --hostpubmd5 */
2141 err = getstr(&config->hostpubmd5, nextarg, DENY_BLANK);
2142 if(!err) {
2143 if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
2144 err = PARAM_BAD_USE;
2145 }
2146 break;
2147 case C_HOSTPUBSHA256: /* --hostpubsha256 */
2148 err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK);
2149 break;
2150 case C_CRLFILE: /* --crlfile */
2151 err = getstr(&config->crlfile, nextarg, DENY_BLANK);
2152 break;
2153 case C_TLSUSER: /* --tlsuser */
2154 if(!feature_tls_srp)
2155 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2156 else
2157 err = getstr(&config->tls_username, nextarg, DENY_BLANK);
2158 cleanarg(clearthis);
2159 break;
2160 case C_TLSPASSWORD: /* --tlspassword */
2161 if(!feature_tls_srp)
2162 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2163 else
2164 err = getstr(&config->tls_password, nextarg, ALLOW_BLANK);
2165 cleanarg(clearthis);
2166 break;
2167 case C_TLSAUTHTYPE: /* --tlsauthtype */
2168 if(!feature_tls_srp)
2169 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2170 else {
2171 err = getstr(&config->tls_authtype, nextarg, DENY_BLANK);
2172 if(!err && strcmp(config->tls_authtype, "SRP"))
2173 err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
2174 }
2175 break;
2176 case C_SSL_ALLOW_BEAST: /* --ssl-allow-beast */
2177 if(feature_ssl)
2178 config->ssl_allow_beast = toggle;
2179 break;
2180 case C_SSL_AUTO_CLIENT_CERT: /* --ssl-auto-client-cert */
2181 if(feature_ssl)
2182 config->ssl_auto_client_cert = toggle;
2183 break;
2184 case C_PROXY_SSL_AUTO_CLIENT_CERT: /* --proxy-ssl-auto-client-cert */
2185 if(feature_ssl)
2186 config->proxy_ssl_auto_client_cert = toggle;
2187 break;
2188 case C_PINNEDPUBKEY: /* --pinnedpubkey */
2189 err = getstr(&config->pinnedpubkey, nextarg, DENY_BLANK);
2190 break;
2191 case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */
2192 err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK);
2193 break;
2194 case C_CERT_STATUS: /* --cert-status */
2195 config->verifystatus = TRUE;
2196 break;
2197 case C_DOH_CERT_STATUS: /* --doh-cert-status */
2198 config->doh_verifystatus = TRUE;
2199 break;
2200 case C_FALSE_START: /* --false-start */
2201 config->falsestart = TRUE;
2202 break;
2203 case C_SSL_NO_REVOKE: /* --ssl-no-revoke */
2204 if(feature_ssl)
2205 config->ssl_no_revoke = TRUE;
2206 break;
2207 case C_SSL_REVOKE_BEST_EFFORT: /* --ssl-revoke-best-effort */
2208 if(feature_ssl)
2209 config->ssl_revoke_best_effort = TRUE;
2210 break;
2211 case C_TCP_FASTOPEN: /* --tcp-fastopen */
2212 config->tcp_fastopen = TRUE;
2213 break;
2214 case C_PROXY_TLSUSER: /* --proxy-tlsuser */
2215 cleanarg(clearthis);
2216 if(!feature_tls_srp)
2217 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2218 else
2219 err = getstr(&config->proxy_tls_username, nextarg, ALLOW_BLANK);
2220 break;
2221 case C_PROXY_TLSPASSWORD: /* --proxy-tlspassword */
2222 cleanarg(clearthis);
2223 if(!feature_tls_srp)
2224 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2225 else
2226 err = getstr(&config->proxy_tls_password, nextarg, DENY_BLANK);
2227 break;
2228 case C_PROXY_TLSAUTHTYPE: /* --proxy-tlsauthtype */
2229 if(!feature_tls_srp)
2230 err = PARAM_LIBCURL_DOESNT_SUPPORT;
2231 else {
2232 err = getstr(&config->proxy_tls_authtype, nextarg, DENY_BLANK);
2233 if(!err && strcmp(config->proxy_tls_authtype, "SRP"))
2234 err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
2235 }
2236 break;
2237 case C_PROXY_CERT: /* --proxy-cert */
2238 cleanarg(clearthis);
2239 GetFileAndPassword(nextarg, &config->proxy_cert,
2240 &config->proxy_key_passwd);
2241 break;
2242 case C_PROXY_CERT_TYPE: /* --proxy-cert-type */
2243 err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK);
2244 break;
2245 case C_PROXY_KEY: /* --proxy-key */
2246 err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK);
2247 break;
2248 case C_PROXY_KEY_TYPE: /* --proxy-key-type */
2249 err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK);
2250 break;
2251 case C_PROXY_PASS: /* --proxy-pass */
2252 err = getstr(&config->proxy_key_passwd, nextarg, ALLOW_BLANK);
2253 cleanarg(clearthis);
2254 break;
2255 case C_PROXY_CIPHERS: /* --proxy-ciphers */
2256 err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK);
2257 break;
2258 case C_PROXY_CRLFILE: /* --proxy-crlfile */
2259 err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK);
2260 break;
2261 case C_PROXY_SSL_ALLOW_BEAST: /* --proxy-ssl-allow-beast */
2262 if(feature_ssl)
2263 config->proxy_ssl_allow_beast = toggle;
2264 break;
2265 case C_LOGIN_OPTIONS: /* --login-options */
2266 err = getstr(&config->login_options, nextarg, ALLOW_BLANK);
2267 break;
2268 case C_PROXY_CACERT: /* --proxy-cacert */
2269 err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK);
2270 break;
2271 case C_PROXY_CAPATH: /* --proxy-capath */
2272 err = getstr(&config->proxy_capath, nextarg, DENY_BLANK);
2273 break;
2274 case C_PROXY_INSECURE: /* --proxy-insecure */
2275 config->proxy_insecure_ok = toggle;
2276 break;
2277 case C_PROXY_TLSV1: /* --proxy-tlsv1 */
2278 /* TLS version 1 for proxy */
2279 config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
2280 break;
2281 case C_SOCKS5_BASIC: /* --socks5-basic */
2282 if(toggle)
2283 config->socks5_auth |= CURLAUTH_BASIC;
2284 else
2285 config->socks5_auth &= ~CURLAUTH_BASIC;
2286 break;
2287 case C_SOCKS5_GSSAPI: /* --socks5-gssapi */
2288 if(toggle)
2289 config->socks5_auth |= CURLAUTH_GSSAPI;
2290 else
2291 config->socks5_auth &= ~CURLAUTH_GSSAPI;
2292 break;
2293 case C_ETAG_SAVE: /* --etag-save */
2294 err = getstr(&config->etag_save_file, nextarg, DENY_BLANK);
2295 break;
2296 case C_ETAG_COMPARE: /* --etag-compare */
2297 err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK);
2298 break;
2299 case C_CURVES: /* --curves */
2300 err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK);
2301 break;
2302 case C_FAIL_EARLY: /* --fail-early */
2303 global->fail_early = toggle;
2304 break;
2305 case C_STYLED_OUTPUT: /* --styled-output */
2306 global->styled_output = toggle;
2307 break;
2308 case C_MAIL_RCPT_ALLOWFAILS: /* --mail-rcpt-allowfails */
2309 config->mail_rcpt_allowfails = toggle;
2310 break;
2311 case C_FAIL_WITH_BODY: /* --fail-with-body */
2312 config->failwithbody = toggle;
2313 if(config->failonerror && config->failwithbody) {
2314 errorf(config->global, "You must select either --fail or "
2315 "--fail-with-body, not both.");
2316 err = PARAM_BAD_USE;
2317 }
2318 break;
2319 case C_REMOVE_ON_ERROR: /* --remove-on-error */
2320 config->rm_partial = toggle;
2321 break;
2322 case C_FAIL: /* --fail */
2323 config->failonerror = toggle;
2324 if(config->failonerror && config->failwithbody) {
2325 errorf(config->global, "You must select either --fail or "
2326 "--fail-with-body, not both.");
2327 err = PARAM_BAD_USE;
2328 }
2329 break;
2330 case C_FORM: /* --form */
2331 case C_FORM_STRING: /* --form-string */
2332 /* "form data" simulation, this is a little advanced so lets do our best
2333 to sort this out slowly and carefully */
2334 if(formparse(config,
2335 nextarg,
2336 &config->mimeroot,
2337 &config->mimecurrent,
2338 (cmd == C_FORM_STRING)?TRUE:FALSE)) /* literal string */
2339 err = PARAM_BAD_USE;
2340 else if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq))
2341 err = PARAM_BAD_USE;
2342 break;
2343 case C_GLOBOFF: /* --globoff */
2344 config->globoff = toggle;
2345 break;
2346 case C_GET: /* --get */
2347 config->use_httpget = toggle;
2348 break;
2349 case C_REQUEST_TARGET: /* --request-target */
2350 err = getstr(&config->request_target, nextarg, DENY_BLANK);
2351 break;
2352 case C_HELP: /* --help */
2353 if(toggle) {
2354 if(*nextarg) {
2355 global->help_category = strdup(nextarg);
2356 if(!global->help_category) {
2357 err = PARAM_NO_MEM;
2358 break;
2359 }
2360 }
2361 err = PARAM_HELP_REQUESTED;
2362 }
2363 /* we now actually support --no-help too! */
2364 break;
2365 case C_HEADER: /* --header */
2366 case C_PROXY_HEADER: /* --proxy-header */
2367 /* A custom header to append to a list */
2368 if(nextarg[0] == '@') {
2369 /* read many headers from a file or stdin */
2370 char *string;
2371 size_t len;
2372 bool use_stdin = !strcmp(&nextarg[1], "-");
2373 FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT);
2374 if(!file) {
2375 errorf(global, "Failed to open %s", &nextarg[1]);
2376 err = PARAM_READ_ERROR;
2377 }
2378 else {
2379 err = file2memory(&string, &len, file);
2380 if(!err && string) {
2381 /* Allow strtok() here since this isn't used threaded */
2382 /* !checksrc! disable BANNEDFUNC 2 */
2383 char *h = strtok(string, "\r\n");
2384 while(h) {
2385 if(cmd == C_PROXY_HEADER) /* --proxy-header */
2386 err = add2list(&config->proxyheaders, h);
2387 else
2388 err = add2list(&config->headers, h);
2389 if(err)
2390 break;
2391 h = strtok(NULL, "\r\n");
2392 }
2393 free(string);
2394 }
2395 if(!use_stdin)
2396 fclose(file);
2397 }
2398 }
2399 else {
2400 if(cmd == C_PROXY_HEADER) /* --proxy-header */
2401 err = add2list(&config->proxyheaders, nextarg);
2402 else
2403 err = add2list(&config->headers, nextarg);
2404 }
2405 break;
2406 case C_INCLUDE: /* --include */
2407 config->show_headers = toggle; /* show the headers as well in the
2408 general output stream */
2409 break;
2410 case C_JUNK_SESSION_COOKIES: /* --junk-session-cookies */
2411 config->cookiesession = toggle;
2412 break;
2413 case C_HEAD: /* --head */
2414 config->no_body = toggle;
2415 config->show_headers = toggle;
2416 if(SetHTTPrequest(config,
2417 (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
2418 &config->httpreq))
2419 err = PARAM_BAD_USE;
2420 break;
2421 case C_REMOTE_HEADER_NAME: /* --remote-header-name */
2422 config->content_disposition = toggle;
2423 break;
2424 case C_INSECURE: /* --insecure */
2425 config->insecure_ok = toggle;
2426 break;
2427 case C_DOH_INSECURE: /* --doh-insecure */
2428 config->doh_insecure_ok = toggle;
2429 break;
2430 case C_CONFIG: /* --config */
2431 if(parseconfig(nextarg, global)) {
2432 errorf(global, "cannot read config from '%s'", nextarg);
2433 err = PARAM_READ_ERROR;
2434 }
2435 break;
2436 case C_LIST_ONLY: /* --list-only */
2437 config->dirlistonly = toggle; /* only list the names of the FTP dir */
2438 break;
2439 case C_LOCATION_TRUSTED: /* --location-trusted */
2440 /* Continue to send authentication (user+password) when following
2441 * locations, even when hostname changed */
2442 config->unrestricted_auth = toggle;
2443 FALLTHROUGH();
2444 case C_LOCATION: /* --location */
2445 config->followlocation = toggle; /* Follow Location: HTTP headers */
2446 break;
2447 case C_MAX_TIME: /* --max-time */
2448 /* specified max time */
2449 err = secs2ms(&config->timeout_ms, nextarg);
2450 break;
2451 case C_MANUAL: /* --manual */
2452 if(toggle) { /* --no-manual shows no manual... */
2453 #ifndef USE_MANUAL
2454 warnf(global,
2455 "built-in manual was disabled at build-time");
2456 #endif
2457 err = PARAM_MANUAL_REQUESTED;
2458 }
2459 break;
2460 case C_NETRC_OPTIONAL: /* --netrc-optional */
2461 config->netrc_opt = toggle;
2462 break;
2463 case C_NETRC_FILE: /* --netrc-file */
2464 err = getstr(&config->netrc_file, nextarg, DENY_BLANK);
2465 break;
2466 case C_NETRC: /* --netrc */
2467 /* pick info from .netrc, if this is used for http, curl will
2468 automatically enforce user+password with the request */
2469 config->netrc = toggle;
2470 break;
2471 case C_BUFFER: /* --buffer */
2472 /* disable the output I/O buffering. note that the option is called
2473 --buffer but is mostly used in the negative form: --no-buffer */
2474 config->nobuffer = longopt ? !toggle : TRUE;
2475 break;
2476 case C_REMOTE_NAME_ALL: /* --remote-name-all */
2477 config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
2478 break;
2479 case C_OUTPUT_DIR: /* --output-dir */
2480 err = getstr(&config->output_dir, nextarg, DENY_BLANK);
2481 break;
2482 case C_CLOBBER: /* --clobber */
2483 config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER;
2484 break;
2485 case C_OUTPUT: /* --output */
2486 case C_REMOTE_NAME: /* --remote-name */
2487 /* output file */
2488 if(!config->url_out)
2489 config->url_out = config->url_list;
2490 if(config->url_out) {
2491 /* there's a node here, if it already is filled-in continue to find
2492 an "empty" node */
2493 while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
2494 config->url_out = config->url_out->next;
2495 }
2496
2497 /* now there might or might not be an available node to fill in! */
2498
2499 if(config->url_out)
2500 /* existing node */
2501 url = config->url_out;
2502 else {
2503 if(!toggle && !config->default_node_flags)
2504 break;
2505 /* there was no free node, create one! */
2506 config->url_out = url = new_getout(config);
2507 }
2508
2509 if(!url) {
2510 err = PARAM_NO_MEM;
2511 break;
2512 }
2513
2514 /* fill in the outfile */
2515 if('o' == letter) {
2516 err = getstr(&url->outfile, nextarg, DENY_BLANK);
2517 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2518 }
2519 else {
2520 url->outfile = NULL; /* leave it */
2521 if(toggle)
2522 url->flags |= GETOUT_USEREMOTE; /* switch on */
2523 else
2524 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2525 }
2526 url->flags |= GETOUT_OUTFILE;
2527 break;
2528 case C_FTP_PORT: /* --ftp-port */
2529 /* This makes the FTP sessions use PORT instead of PASV */
2530 /* use <eth0> or <192.168.10.10> style addresses. Anything except
2531 this will make us try to get the "default" address.
2532 NOTE: this is a changed behavior since the released 4.1!
2533 */
2534 err = getstr(&config->ftpport, nextarg, DENY_BLANK);
2535 break;
2536 case C_PROXYTUNNEL: /* --proxytunnel */
2537 /* proxy tunnel for non-http protocols */
2538 config->proxytunnel = toggle;
2539 break;
2540
2541 case C_DISABLE: /* --disable */
2542 /* if used first, already taken care of, we do it like this so we don't
2543 cause an error! */
2544 break;
2545 case C_QUOTE: /* --quote */
2546 /* QUOTE command to send to FTP server */
2547 switch(nextarg[0]) {
2548 case '-':
2549 /* prefixed with a dash makes it a POST TRANSFER one */
2550 nextarg++;
2551 err = add2list(&config->postquote, nextarg);
2552 break;
2553 case '+':
2554 /* prefixed with a plus makes it a just-before-transfer one */
2555 nextarg++;
2556 err = add2list(&config->prequote, nextarg);
2557 break;
2558 default:
2559 err = add2list(&config->quote, nextarg);
2560 break;
2561 }
2562 break;
2563 case C_RANGE: /* --range */
2564 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
2565 (and won't actually be range by definition). The man page previously
2566 claimed that to be a good way, why this code is added to work-around
2567 it. */
2568 if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
2569 char buffer[32];
2570 if(curlx_strtoofft(nextarg, NULL, 10, &value)) {
2571 warnf(global, "unsupported range point");
2572 err = PARAM_BAD_USE;
2573 }
2574 else {
2575 warnf(global,
2576 "A specified range MUST include at least one dash (-). "
2577 "Appending one for you");
2578 msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-",
2579 value);
2580 Curl_safefree(config->range);
2581 config->range = strdup(buffer);
2582 if(!config->range)
2583 err = PARAM_NO_MEM;
2584 }
2585 }
2586 else {
2587 /* byte range requested */
2588 const char *tmp_range = nextarg;
2589 while(*tmp_range) {
2590 if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
2591 warnf(global, "Invalid character is found in given range. "
2592 "A specified range MUST have only digits in "
2593 "\'start\'-\'stop\'. The server's response to this "
2594 "request is uncertain.");
2595 break;
2596 }
2597 tmp_range++;
2598 }
2599 err = getstr(&config->range, nextarg, DENY_BLANK);
2600 }
2601 break;
2602 case C_REMOTE_TIME: /* --remote-time */
2603 /* use remote file's time */
2604 config->remote_time = toggle;
2605 break;
2606 case C_SILENT: /* --silent */
2607 global->silent = toggle;
2608 break;
2609 case C_SHOW_ERROR: /* --show-error */
2610 global->showerror = toggle;
2611 break;
2612 case C_TELNET_OPTION: /* --telnet-option */
2613 /* Telnet options */
2614 err = add2list(&config->telnet_options, nextarg);
2615 break;
2616 case C_UPLOAD_FILE: /* --upload-file */
2617 /* we are uploading */
2618 if(!config->url_ul)
2619 config->url_ul = config->url_list;
2620 if(config->url_ul) {
2621 /* there's a node here, if it already is filled-in continue to find
2622 an "empty" node */
2623 while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
2624 config->url_ul = config->url_ul->next;
2625 }
2626
2627 /* now there might or might not be an available node to fill in! */
2628
2629 if(config->url_ul)
2630 /* existing node */
2631 url = config->url_ul;
2632 else
2633 /* there was no free node, create one! */
2634 config->url_ul = url = new_getout(config);
2635
2636 if(!url) {
2637 err = PARAM_NO_MEM;
2638 break;
2639 }
2640
2641 url->flags |= GETOUT_UPLOAD; /* mark -T used */
2642 if(!*nextarg)
2643 url->flags |= GETOUT_NOUPLOAD;
2644 else {
2645 /* "-" equals stdin, but keep the string around for now */
2646 err = getstr(&url->infile, nextarg, DENY_BLANK);
2647 }
2648 break;
2649 case C_USER: /* --user */
2650 /* user:password */
2651 err = getstr(&config->userpwd, nextarg, ALLOW_BLANK);
2652 cleanarg(clearthis);
2653 break;
2654 case C_PROXY_USER: /* --proxy-user */
2655 /* Proxy user:password */
2656 err = getstr(&config->proxyuserpwd, nextarg, ALLOW_BLANK);
2657 cleanarg(clearthis);
2658 break;
2659 case C_VERBOSE: /* --verbose */
2660 if(toggle) {
2661 /* the '%' thing here will cause the trace get sent to stderr */
2662 Curl_safefree(global->trace_dump);
2663 global->trace_dump = strdup("%");
2664 if(!global->trace_dump)
2665 err = PARAM_NO_MEM;
2666 else {
2667 if(global->tracetype && (global->tracetype != TRACE_PLAIN))
2668 warnf(global,
2669 "-v, --verbose overrides an earlier trace/verbose option");
2670 global->tracetype = TRACE_PLAIN;
2671 }
2672 }
2673 else
2674 /* verbose is disabled here */
2675 global->tracetype = TRACE_NONE;
2676 break;
2677 case C_VERSION: /* --version */
2678 if(toggle) /* --no-version yields no output! */
2679 err = PARAM_VERSION_INFO_REQUESTED;
2680 break;
2681 case C_WRITE_OUT: /* --write-out */
2682 /* get the output string */
2683 if('@' == *nextarg) {
2684 /* the data begins with a '@' letter, it means that a file name
2685 or - (stdin) follows */
2686 FILE *file;
2687 const char *fname;
2688 nextarg++; /* pass the @ */
2689 if(!strcmp("-", nextarg)) {
2690 fname = "<stdin>";
2691 file = stdin;
2692 }
2693 else {
2694 fname = nextarg;
2695 file = fopen(fname, FOPEN_READTEXT);
2696 if(!file) {
2697 errorf(global, "Failed to open %s", fname);
2698 err = PARAM_READ_ERROR;
2699 break;
2700 }
2701 }
2702 Curl_safefree(config->writeout);
2703 err = file2string(&config->writeout, file);
2704 if(file && (file != stdin))
2705 fclose(file);
2706 if(err)
2707 break;
2708 if(!config->writeout)
2709 warnf(global, "Failed to read %s", fname);
2710 }
2711 else
2712 err = getstr(&config->writeout, nextarg, ALLOW_BLANK);
2713 break;
2714 case C_PREPROXY: /* --preproxy */
2715 err = getstr(&config->preproxy, nextarg, DENY_BLANK);
2716 break;
2717 case C_PROXY: /* --proxy */
2718 /* --proxy */
2719 err = getstr(&config->proxy, nextarg, ALLOW_BLANK);
2720 if(config->proxyver != CURLPROXY_HTTPS2)
2721 config->proxyver = CURLPROXY_HTTP;
2722 break;
2723 case C_REQUEST: /* --request */
2724 /* set custom request */
2725 err = getstr(&config->customrequest, nextarg, DENY_BLANK);
2726 break;
2727 case C_SPEED_TIME: /* --speed-time */
2728 /* low speed time */
2729 err = str2unum(&config->low_speed_time, nextarg);
2730 if(!err && !config->low_speed_limit)
2731 config->low_speed_limit = 1;
2732 break;
2733 case C_SPEED_LIMIT: /* --speed-limit */
2734 /* low speed limit */
2735 err = str2unum(&config->low_speed_limit, nextarg);
2736 if(!err && !config->low_speed_time)
2737 config->low_speed_time = 30;
2738 break;
2739 case C_PARALLEL: /* --parallel */
2740 global->parallel = toggle;
2741 break;
2742 case C_PARALLEL_MAX: { /* --parallel-max */
2743 long val;
2744 err = str2unum(&val, nextarg);
2745 if(err)
2746 break;
2747 if(val > MAX_PARALLEL)
2748 global->parallel_max = MAX_PARALLEL;
2749 else if(val < 1)
2750 global->parallel_max = PARALLEL_DEFAULT;
2751 else
2752 global->parallel_max = (unsigned short)val;
2753 break;
2754 }
2755 case C_PARALLEL_IMMEDIATE: /* --parallel-immediate */
2756 global->parallel_connect = toggle;
2757 break;
2758 case C_TIME_COND: /* --time-cond */
2759 switch(*nextarg) {
2760 case '+':
2761 nextarg++;
2762 FALLTHROUGH();
2763 default:
2764 /* If-Modified-Since: (section 14.28 in RFC2068) */
2765 config->timecond = CURL_TIMECOND_IFMODSINCE;
2766 break;
2767 case '-':
2768 /* If-Unmodified-Since: (section 14.24 in RFC2068) */
2769 config->timecond = CURL_TIMECOND_IFUNMODSINCE;
2770 nextarg++;
2771 break;
2772 case '=':
2773 /* Last-Modified: (section 14.29 in RFC2068) */
2774 config->timecond = CURL_TIMECOND_LASTMOD;
2775 nextarg++;
2776 break;
2777 }
2778 now = time(NULL);
2779 config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
2780 if(-1 == config->condtime) {
2781 /* now let's see if it is a file name to get the time from instead! */
2782 rc = getfiletime(nextarg, global, &value);
2783 if(!rc)
2784 /* pull the time out from the file */
2785 config->condtime = value;
2786 else {
2787 /* failed, remove time condition */
2788 config->timecond = CURL_TIMECOND_NONE;
2789 warnf(global,
2790 "Illegal date format for -z, --time-cond (and not "
2791 "a file name). Disabling time condition. "
2792 "See curl_getdate(3) for valid date syntax.");
2793 }
2794 }
2795 break;
2796 default: /* unknown flag */
2797 err = PARAM_OPTION_UNKNOWN;
2798 break;
2799 }
2800 a = NULL;
2801
2802 } while(!longopt && !singleopt && *++parse && !*usedarg && !err);
2803
2804 error:
2805 if(nextalloc)
2806 free(nextarg);
2807 return err;
2808 }
2809
parse_args(struct GlobalConfig * global,int argc,argv_item_t argv[])2810 ParameterError parse_args(struct GlobalConfig *global, int argc,
2811 argv_item_t argv[])
2812 {
2813 int i;
2814 bool stillflags;
2815 char *orig_opt = NULL;
2816 ParameterError result = PARAM_OK;
2817 struct OperationConfig *config = global->first;
2818
2819 for(i = 1, stillflags = TRUE; i < argc && !result; i++) {
2820 orig_opt = curlx_convert_tchar_to_UTF8(argv[i]);
2821 if(!orig_opt)
2822 return PARAM_NO_MEM;
2823
2824 if(stillflags && ('-' == orig_opt[0])) {
2825 bool passarg;
2826
2827 if(!strcmp("--", orig_opt))
2828 /* This indicates the end of the flags and thus enables the
2829 following (URL) argument to start with -. */
2830 stillflags = FALSE;
2831 else {
2832 char *nextarg = NULL;
2833 if(i < (argc - 1)) {
2834 nextarg = curlx_convert_tchar_to_UTF8(argv[i + 1]);
2835 if(!nextarg) {
2836 curlx_unicodefree(orig_opt);
2837 return PARAM_NO_MEM;
2838 }
2839 }
2840
2841 result = getparameter(orig_opt, nextarg, argv[i + 1], &passarg,
2842 global, config);
2843
2844 curlx_unicodefree(nextarg);
2845 config = global->last;
2846 if(result == PARAM_NEXT_OPERATION) {
2847 /* Reset result as PARAM_NEXT_OPERATION is only used here and not
2848 returned from this function */
2849 result = PARAM_OK;
2850
2851 if(config->url_list && config->url_list->url) {
2852 /* Allocate the next config */
2853 config->next = malloc(sizeof(struct OperationConfig));
2854 if(config->next) {
2855 /* Initialise the newly created config */
2856 config_init(config->next);
2857
2858 /* Set the global config pointer */
2859 config->next->global = global;
2860
2861 /* Update the last config pointer */
2862 global->last = config->next;
2863
2864 /* Move onto the new config */
2865 config->next->prev = config;
2866 config = config->next;
2867 }
2868 else
2869 result = PARAM_NO_MEM;
2870 }
2871 else {
2872 errorf(global, "missing URL before --next");
2873 result = PARAM_BAD_USE;
2874 }
2875 }
2876 else if(!result && passarg)
2877 i++; /* we're supposed to skip this */
2878 }
2879 }
2880 else {
2881 bool used;
2882
2883 /* Just add the URL please */
2884 result = getparameter("--url", orig_opt, argv[i], &used, global, config);
2885 }
2886
2887 if(!result)
2888 curlx_unicodefree(orig_opt);
2889 }
2890
2891 if(!result && config->content_disposition) {
2892 if(config->show_headers)
2893 result = PARAM_CONTDISP_SHOW_HEADER;
2894 else if(config->resume_from_current)
2895 result = PARAM_CONTDISP_RESUME_FROM;
2896 }
2897
2898 if(result && result != PARAM_HELP_REQUESTED &&
2899 result != PARAM_MANUAL_REQUESTED &&
2900 result != PARAM_VERSION_INFO_REQUESTED &&
2901 result != PARAM_ENGINES_REQUESTED) {
2902 const char *reason = param2text(result);
2903
2904 if(orig_opt && strcmp(":", orig_opt))
2905 helpf(tool_stderr, "option %s: %s", orig_opt, reason);
2906 else
2907 helpf(tool_stderr, "%s", reason);
2908 }
2909
2910 curlx_unicodefree(orig_opt);
2911 return result;
2912 }
2913