Annotation of embedaddon/curl/src/tool_operate.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, 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.haxx.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: ***************************************************************************/
22: #include "tool_setup.h"
23:
24: #ifdef HAVE_FCNTL_H
25: # include <fcntl.h>
26: #endif
27:
28: #ifdef HAVE_LOCALE_H
29: # include <locale.h>
30: #endif
31:
32: #ifdef HAVE_SYS_SELECT_H
33: # include <sys/select.h>
34: #elif defined(HAVE_UNISTD_H)
35: # include <unistd.h>
36: #endif
37:
38: #ifdef __VMS
39: # include <fabdef.h>
40: #endif
41:
42: #ifdef __AMIGA__
43: # include <proto/dos.h>
44: #endif
45:
46: #include "strcase.h"
47:
48: #define ENABLE_CURLX_PRINTF
49: /* use our own printf() functions */
50: #include "curlx.h"
51:
52: #include "tool_binmode.h"
53: #include "tool_cfgable.h"
54: #include "tool_cb_dbg.h"
55: #include "tool_cb_hdr.h"
56: #include "tool_cb_prg.h"
57: #include "tool_cb_rea.h"
58: #include "tool_cb_see.h"
59: #include "tool_cb_wrt.h"
60: #include "tool_dirhie.h"
61: #include "tool_doswin.h"
62: #include "tool_easysrc.h"
63: #include "tool_filetime.h"
64: #include "tool_getparam.h"
65: #include "tool_helpers.h"
66: #include "tool_homedir.h"
67: #include "tool_libinfo.h"
68: #include "tool_main.h"
69: #include "tool_metalink.h"
70: #include "tool_msgs.h"
71: #include "tool_operate.h"
72: #include "tool_operhlp.h"
73: #include "tool_paramhlp.h"
74: #include "tool_parsecfg.h"
75: #include "tool_setopt.h"
76: #include "tool_sleep.h"
77: #include "tool_urlglob.h"
78: #include "tool_util.h"
79: #include "tool_writeout.h"
80: #include "tool_xattr.h"
81: #include "tool_vms.h"
82: #include "tool_help.h"
83: #include "tool_hugehelp.h"
84: #include "tool_progress.h"
85:
86: #include "memdebug.h" /* keep this as LAST include */
87:
88: #ifdef CURLDEBUG
89: /* libcurl's debug builds provide an extra function */
90: CURLcode curl_easy_perform_ev(CURL *easy);
91: #endif
92:
93: #define CURLseparator "--_curl_--"
94:
95: #ifndef O_BINARY
96: /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
97: source code but yet it doesn't ruin anything */
98: # define O_BINARY 0
99: #endif
100:
101: #define CURL_CA_CERT_ERRORMSG \
102: "More details here: https://curl.haxx.se/docs/sslcerts.html\n\n" \
103: "curl failed to verify the legitimacy of the server and therefore " \
104: "could not\nestablish a secure connection to it. To learn more about " \
105: "this situation and\nhow to fix it, please visit the web page mentioned " \
106: "above.\n"
107:
108: static CURLcode single_transfer(struct GlobalConfig *global,
109: struct OperationConfig *config,
110: CURLSH *share,
111: bool capath_from_env,
112: bool *added);
113: static CURLcode create_transfer(struct GlobalConfig *global,
114: CURLSH *share,
115: bool *added);
116:
117: static bool is_fatal_error(CURLcode code)
118: {
119: switch(code) {
120: case CURLE_FAILED_INIT:
121: case CURLE_OUT_OF_MEMORY:
122: case CURLE_UNKNOWN_OPTION:
123: case CURLE_FUNCTION_NOT_FOUND:
124: case CURLE_BAD_FUNCTION_ARGUMENT:
125: /* critical error */
126: return TRUE;
127: default:
128: break;
129: }
130:
131: /* no error or not critical */
132: return FALSE;
133: }
134:
135: /*
136: * Check if a given string is a PKCS#11 URI
137: */
138: static bool is_pkcs11_uri(const char *string)
139: {
140: if(curl_strnequal(string, "pkcs11:", 7)) {
141: return TRUE;
142: }
143: else {
144: return FALSE;
145: }
146: }
147:
148: #ifdef __VMS
149: /*
150: * get_vms_file_size does what it takes to get the real size of the file
151: *
152: * For fixed files, find out the size of the EOF block and adjust.
153: *
154: * For all others, have to read the entire file in, discarding the contents.
155: * Most posted text files will be small, and binary files like zlib archives
156: * and CD/DVD images should be either a STREAM_LF format or a fixed format.
157: *
158: */
159: static curl_off_t vms_realfilesize(const char *name,
160: const struct_stat *stat_buf)
161: {
162: char buffer[8192];
163: curl_off_t count;
164: int ret_stat;
165: FILE * file;
166:
167: /* !checksrc! disable FOPENMODE 1 */
168: file = fopen(name, "r"); /* VMS */
169: if(file == NULL) {
170: return 0;
171: }
172: count = 0;
173: ret_stat = 1;
174: while(ret_stat > 0) {
175: ret_stat = fread(buffer, 1, sizeof(buffer), file);
176: if(ret_stat != 0)
177: count += ret_stat;
178: }
179: fclose(file);
180:
181: return count;
182: }
183:
184: /*
185: *
186: * VmsSpecialSize checks to see if the stat st_size can be trusted and
187: * if not to call a routine to get the correct size.
188: *
189: */
190: static curl_off_t VmsSpecialSize(const char *name,
191: const struct_stat *stat_buf)
192: {
193: switch(stat_buf->st_fab_rfm) {
194: case FAB$C_VAR:
195: case FAB$C_VFC:
196: return vms_realfilesize(name, stat_buf);
197: break;
198: default:
199: return stat_buf->st_size;
200: }
201: }
202: #endif /* __VMS */
203:
204: #define BUFFER_SIZE (100*1024)
205:
206: struct per_transfer *transfers; /* first node */
207: static struct per_transfer *transfersl; /* last node */
208:
209: /* add_per_transfer creates a new 'per_transfer' node in the linked
210: list of transfers */
211: static CURLcode add_per_transfer(struct per_transfer **per)
212: {
213: struct per_transfer *p;
214: p = calloc(sizeof(struct per_transfer), 1);
215: if(!p)
216: return CURLE_OUT_OF_MEMORY;
217: if(!transfers)
218: /* first entry */
219: transfersl = transfers = p;
220: else {
221: /* make the last node point to the new node */
222: transfersl->next = p;
223: /* make the new node point back to the formerly last node */
224: p->prev = transfersl;
225: /* move the last node pointer to the new entry */
226: transfersl = p;
227: }
228: *per = p;
229: all_xfers++; /* count total number of transfers added */
230: return CURLE_OK;
231: }
232:
233: /* Remove the specified transfer from the list (and free it), return the next
234: in line */
235: static struct per_transfer *del_per_transfer(struct per_transfer *per)
236: {
237: struct per_transfer *n;
238: struct per_transfer *p;
239: DEBUGASSERT(transfers);
240: DEBUGASSERT(transfersl);
241: DEBUGASSERT(per);
242:
243: n = per->next;
244: p = per->prev;
245:
246: if(p)
247: p->next = n;
248: else
249: transfers = n;
250:
251: if(n)
252: n->prev = p;
253: else
254: transfersl = p;
255:
256: free(per);
257:
258: return n;
259: }
260:
261: static CURLcode pre_transfer(struct GlobalConfig *global,
262: struct per_transfer *per)
263: {
264: curl_off_t uploadfilesize = -1;
265: struct_stat fileinfo;
266: CURLcode result = CURLE_OK;
267:
268: if(per->separator_err)
269: fprintf(global->errors, "%s\n", per->separator_err);
270: if(per->separator)
271: printf("%s\n", per->separator);
272:
273: if(per->uploadfile && !stdin_upload(per->uploadfile)) {
274: /* VMS Note:
275: *
276: * Reading binary from files can be a problem... Only FIXED, VAR
277: * etc WITHOUT implied CC will work Others need a \n appended to a
278: * line
279: *
280: * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
281: * fixed file with implied CC needs to have a byte added for every
282: * record processed, this can by derived from Filesize & recordsize
283: * for VARiable record files the records need to be counted! for
284: * every record add 1 for linefeed and subtract 2 for the record
285: * header for VARIABLE header files only the bare record data needs
286: * to be considered with one appended if implied CC
287: */
288: #ifdef __VMS
289: /* Calculate the real upload size for VMS */
290: per->infd = -1;
291: if(stat(per->uploadfile, &fileinfo) == 0) {
292: fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
293: switch(fileinfo.st_fab_rfm) {
294: case FAB$C_VAR:
295: case FAB$C_VFC:
296: case FAB$C_STMCR:
297: per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
298: break;
299: default:
300: per->infd = open(per->uploadfile, O_RDONLY | O_BINARY,
301: "rfm=stmlf", "ctx=stm");
302: }
303: }
304: if(per->infd == -1)
305: #else
306: per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
307: if((per->infd == -1) || fstat(per->infd, &fileinfo))
308: #endif
309: {
310: helpf(global->errors, "Can't open '%s'!\n", per->uploadfile);
311: if(per->infd != -1) {
312: close(per->infd);
313: per->infd = STDIN_FILENO;
314: }
315: return CURLE_READ_ERROR;
316: }
317: per->infdopen = TRUE;
318:
319: /* we ignore file size for char/block devices, sockets, etc. */
320: if(S_ISREG(fileinfo.st_mode))
321: uploadfilesize = fileinfo.st_size;
322:
323: if(uploadfilesize != -1)
324: my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
325: per->input.fd = per->infd;
326: }
327: return result;
328: }
329:
330: /*
331: * Call this after a transfer has completed.
332: */
333: static CURLcode post_per_transfer(struct GlobalConfig *global,
334: struct per_transfer *per,
335: CURLcode result,
336: bool *retryp)
337: {
338: struct OutStruct *outs = &per->outs;
339: CURL *curl = per->curl;
340: struct OperationConfig *config = per->config;
341:
342: if(!curl || !config)
343: return result;
344:
345: *retryp = FALSE;
346:
347: if(per->infdopen)
348: close(per->infd);
349:
350: #ifdef __VMS
351: if(is_vms_shell()) {
352: /* VMS DCL shell behavior */
353: if(!global->showerror)
354: vms_show = VMSSTS_HIDE;
355: }
356: else
357: #endif
358: if(config->synthetic_error) {
359: ;
360: }
361: else if(result && global->showerror) {
362: fprintf(global->errors, "curl: (%d) %s\n", result,
363: (per->errorbuffer[0]) ? per->errorbuffer :
364: curl_easy_strerror(result));
365: if(result == CURLE_PEER_FAILED_VERIFICATION)
366: fputs(CURL_CA_CERT_ERRORMSG, global->errors);
367: }
368:
369: /* Set file extended attributes */
370: if(!result && config->xattr && outs->fopened && outs->stream) {
371: int rc = fwrite_xattr(curl, fileno(outs->stream));
372: if(rc)
373: warnf(config->global, "Error setting extended attributes: %s\n",
374: strerror(errno));
375: }
376:
377: if(!result && !outs->stream && !outs->bytes) {
378: /* we have received no data despite the transfer was successful
379: ==> force cration of an empty output file (if an output file
380: was specified) */
381: long cond_unmet = 0L;
382: /* do not create (or even overwrite) the file in case we get no
383: data because of unmet condition */
384: curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet);
385: if(!cond_unmet && !tool_create_output_file(outs, config))
386: result = CURLE_WRITE_ERROR;
387: }
388:
389: if(!outs->s_isreg && outs->stream) {
390: /* Dump standard stream buffered data */
391: int rc = fflush(outs->stream);
392: if(!result && rc) {
393: /* something went wrong in the writing process */
394: result = CURLE_WRITE_ERROR;
395: fprintf(global->errors, "(%d) Failed writing body\n", result);
396: }
397: }
398:
399: #ifdef USE_METALINK
400: if(per->metalink && !per->metalink_next_res)
401: fprintf(global->errors, "Metalink: fetching (%s) from (%s) OK\n",
402: per->mlfile->filename, per->this_url);
403:
404: if(!per->metalink && config->use_metalink && result == CURLE_OK) {
405: int rv = parse_metalink(config, outs, per->this_url);
406: if(!rv) {
407: fprintf(config->global->errors, "Metalink: parsing (%s) OK\n",
408: per->this_url);
409: }
410: else if(rv == -1)
411: fprintf(config->global->errors, "Metalink: parsing (%s) FAILED\n",
412: per->this_url);
413: }
414: else if(per->metalink && result == CURLE_OK && !per->metalink_next_res) {
415: int rv;
416: (void)fflush(outs->stream);
417: rv = metalink_check_hash(global, per->mlfile, outs->filename);
418: if(!rv)
419: per->metalink_next_res = 1;
420: }
421: #endif /* USE_METALINK */
422:
423: #ifdef USE_METALINK
424: if(outs->metalink_parser)
425: metalink_parser_context_delete(outs->metalink_parser);
426: #endif /* USE_METALINK */
427:
428: if(outs->is_cd_filename && outs->stream && !global->mute &&
429: outs->filename)
430: printf("curl: Saved to filename '%s'\n", outs->filename);
431:
432: /* if retry-max-time is non-zero, make sure we haven't exceeded the
433: time */
434: if(per->retry_numretries &&
435: (!config->retry_maxtime ||
436: (tvdiff(tvnow(), per->retrystart) <
437: config->retry_maxtime*1000L)) ) {
438: enum {
439: RETRY_NO,
440: RETRY_TIMEOUT,
441: RETRY_CONNREFUSED,
442: RETRY_HTTP,
443: RETRY_FTP,
444: RETRY_LAST /* not used */
445: } retry = RETRY_NO;
446: long response;
447: if((CURLE_OPERATION_TIMEDOUT == result) ||
448: (CURLE_COULDNT_RESOLVE_HOST == result) ||
449: (CURLE_COULDNT_RESOLVE_PROXY == result) ||
450: (CURLE_FTP_ACCEPT_TIMEOUT == result))
451: /* retry timeout always */
452: retry = RETRY_TIMEOUT;
453: else if(config->retry_connrefused &&
454: (CURLE_COULDNT_CONNECT == result)) {
455: long oserrno;
456: curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno);
457: if(ECONNREFUSED == oserrno)
458: retry = RETRY_CONNREFUSED;
459: }
460: else if((CURLE_OK == result) ||
461: (config->failonerror &&
462: (CURLE_HTTP_RETURNED_ERROR == result))) {
463: /* If it returned OK. _or_ failonerror was enabled and it
464: returned due to such an error, check for HTTP transient
465: errors to retry on. */
466: long protocol;
467: curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
468: if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) {
469: /* This was HTTP(S) */
470: curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
471:
472: switch(response) {
473: case 429: /* Too Many Requests (RFC6585) */
474: case 500: /* Internal Server Error */
475: case 502: /* Bad Gateway */
476: case 503: /* Service Unavailable */
477: case 504: /* Gateway Timeout */
478: retry = RETRY_HTTP;
479: /*
480: * At this point, we have already written data to the output
481: * file (or terminal). If we write to a file, we must rewind
482: * or close/re-open the file so that the next attempt starts
483: * over from the beginning.
484: *
485: * TODO: similar action for the upload case. We might need
486: * to start over reading from a previous point if we have
487: * uploaded something when this was returned.
488: */
489: break;
490: }
491: }
492: } /* if CURLE_OK */
493: else if(result) {
494: long protocol;
495:
496: curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
497: curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
498:
499: if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) &&
500: response / 100 == 4)
501: /*
502: * This is typically when the FTP server only allows a certain
503: * amount of users and we are not one of them. All 4xx codes
504: * are transient.
505: */
506: retry = RETRY_FTP;
507: }
508:
509: if(retry) {
510: long sleeptime = 0;
511: curl_off_t retry_after = 0;
512: static const char * const m[]={
513: NULL,
514: "timeout",
515: "connection refused",
516: "HTTP error",
517: "FTP error"
518: };
519:
520: sleeptime = per->retry_sleep;
521: if(RETRY_HTTP == retry) {
522: curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after);
523: if(retry_after) {
524: /* store in a 'long', make sure it doesn't overflow */
525: if(retry_after > LONG_MAX/1000)
526: sleeptime = LONG_MAX;
527: else
528: sleeptime = (long)retry_after * 1000; /* milliseconds */
529: }
530: }
531: warnf(config->global, "Transient problem: %s "
532: "Will retry in %ld seconds. "
533: "%ld retries left.\n",
534: m[retry], sleeptime/1000L, per->retry_numretries);
535:
536: per->retry_numretries--;
537: tool_go_sleep(sleeptime);
538: if(!config->retry_delay) {
539: per->retry_sleep *= 2;
540: if(per->retry_sleep > RETRY_SLEEP_MAX)
541: per->retry_sleep = RETRY_SLEEP_MAX;
542: }
543: if(outs->bytes && outs->filename && outs->stream) {
544: int rc;
545: /* We have written data to a output file, we truncate file
546: */
547: if(!global->mute)
548: fprintf(global->errors, "Throwing away %"
549: CURL_FORMAT_CURL_OFF_T " bytes\n",
550: outs->bytes);
551: fflush(outs->stream);
552: /* truncate file at the position where we started appending */
553: #ifdef HAVE_FTRUNCATE
554: if(ftruncate(fileno(outs->stream), outs->init)) {
555: /* when truncate fails, we can't just append as then we'll
556: create something strange, bail out */
557: if(!global->mute)
558: fprintf(global->errors,
559: "failed to truncate, exiting\n");
560: return CURLE_WRITE_ERROR;
561: }
562: /* now seek to the end of the file, the position where we
563: just truncated the file in a large file-safe way */
564: rc = fseek(outs->stream, 0, SEEK_END);
565: #else
566: /* ftruncate is not available, so just reposition the file
567: to the location we would have truncated it. This won't
568: work properly with large files on 32-bit systems, but
569: most of those will have ftruncate. */
570: rc = fseek(outs->stream, (long)outs->init, SEEK_SET);
571: #endif
572: if(rc) {
573: if(!global->mute)
574: fprintf(global->errors,
575: "failed seeking to end of file, exiting\n");
576: return CURLE_WRITE_ERROR;
577: }
578: outs->bytes = 0; /* clear for next round */
579: }
580: *retryp = TRUE; /* curl_easy_perform loop */
581: return CURLE_OK;
582: }
583: } /* if retry_numretries */
584: else if(per->metalink) {
585: /* Metalink: Decide to try the next resource or not. Try the next resource
586: if download was not successful. */
587: long response;
588: if(CURLE_OK == result) {
589: /* TODO We want to try next resource when download was
590: not successful. How to know that? */
591: char *effective_url = NULL;
592: curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
593: if(effective_url &&
594: curl_strnequal(effective_url, "http", 4)) {
595: /* This was HTTP(S) */
596: curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
597: if(response != 200 && response != 206) {
598: per->metalink_next_res = 1;
599: fprintf(global->errors,
600: "Metalink: fetching (%s) from (%s) FAILED "
601: "(HTTP status code %ld)\n",
602: per->mlfile->filename, per->this_url, response);
603: }
604: }
605: }
606: else {
607: per->metalink_next_res = 1;
608: fprintf(global->errors,
609: "Metalink: fetching (%s) from (%s) FAILED (%s)\n",
610: per->mlfile->filename, per->this_url,
611: curl_easy_strerror(result));
612: }
613: }
614:
615: if((global->progressmode == CURL_PROGRESS_BAR) &&
616: per->progressbar.calls)
617: /* if the custom progress bar has been displayed, we output a
618: newline here */
619: fputs("\n", per->progressbar.out);
620:
621: if(config->writeout)
622: ourWriteOut(per->curl, &per->outs, config->writeout);
623:
624: /* Close the outs file */
625: if(outs->fopened && outs->stream) {
626: int rc = fclose(outs->stream);
627: if(!result && rc) {
628: /* something went wrong in the writing process */
629: result = CURLE_WRITE_ERROR;
630: fprintf(global->errors, "(%d) Failed writing body\n", result);
631: }
632: }
633:
634: /* File time can only be set _after_ the file has been closed */
635: if(!result && config->remote_time && outs->s_isreg && outs->filename) {
636: /* Ask libcurl if we got a remote file time */
637: curl_off_t filetime = -1;
638: curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime);
639: setfiletime(filetime, outs->filename, config->global->errors);
640: }
641:
642: /* Close function-local opened file descriptors */
643: if(per->heads.fopened && per->heads.stream)
644: fclose(per->heads.stream);
645:
646: if(per->heads.alloc_filename)
647: Curl_safefree(per->heads.filename);
648:
649: if(per->etag_save.fopened && per->etag_save.stream)
650: fclose(per->etag_save.stream);
651:
652: if(per->etag_save.alloc_filename)
653: Curl_safefree(per->etag_save.filename);
654:
655: curl_easy_cleanup(per->curl);
656: if(outs->alloc_filename)
657: free(outs->filename);
658: free(per->this_url);
659: free(per->separator_err);
660: free(per->separator);
661: free(per->outfile);
662: free(per->uploadfile);
663:
664: return CURLE_OK;
665: }
666:
667: static void single_transfer_cleanup(struct OperationConfig *config)
668: {
669: if(config) {
670: struct State *state = &config->state;
671: if(state->urls) {
672: /* Free list of remaining URLs */
673: glob_cleanup(state->urls);
674: state->urls = NULL;
675: }
676: Curl_safefree(state->outfiles);
677: Curl_safefree(state->httpgetfields);
678: Curl_safefree(state->uploadfile);
679: if(state->inglob) {
680: /* Free list of globbed upload files */
681: glob_cleanup(state->inglob);
682: state->inglob = NULL;
683: }
684: }
685: }
686:
687: /* create the next (singular) transfer */
688:
689: static CURLcode single_transfer(struct GlobalConfig *global,
690: struct OperationConfig *config,
691: CURLSH *share,
692: bool capath_from_env,
693: bool *added)
694: {
695: CURLcode result = CURLE_OK;
696: struct getout *urlnode;
697: metalinkfile *mlfile_last = NULL;
698: bool orig_noprogress = global->noprogress;
699: bool orig_isatty = global->isatty;
700: struct State *state = &config->state;
701: char *httpgetfields = state->httpgetfields;
702: *added = FALSE; /* not yet */
703:
704: if(config->postfields) {
705: if(config->use_httpget) {
706: if(!httpgetfields) {
707: /* Use the postfields data for a http get */
708: httpgetfields = state->httpgetfields = strdup(config->postfields);
709: Curl_safefree(config->postfields);
710: if(!httpgetfields) {
711: errorf(global, "out of memory\n");
712: result = CURLE_OUT_OF_MEMORY;
713: }
714: else if(SetHTTPrequest(config,
715: (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
716: &config->httpreq)) {
717: result = CURLE_FAILED_INIT;
718: }
719: }
720: }
721: else {
722: if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
723: result = CURLE_FAILED_INIT;
724: }
725: if(result) {
726: single_transfer_cleanup(config);
727: return result;
728: }
729: }
730: if(!state->urlnode) {
731: /* first time caller, setup things */
732: state->urlnode = config->url_list;
733: state->infilenum = 1;
734: }
735:
736: while(config->state.urlnode) {
737: char *infiles; /* might be a glob pattern */
738: URLGlob *inglob = state->inglob;
739: bool metalink = FALSE; /* metalink download? */
740: metalinkfile *mlfile;
741: metalink_resource *mlres;
742:
743: urlnode = config->state.urlnode;
744: if(urlnode->flags & GETOUT_METALINK) {
745: metalink = 1;
746: if(mlfile_last == NULL) {
747: mlfile_last = config->metalinkfile_list;
748: }
749: mlfile = mlfile_last;
750: mlfile_last = mlfile_last->next;
751: mlres = mlfile->resource;
752: }
753: else {
754: mlfile = NULL;
755: mlres = NULL;
756: }
757:
758: /* urlnode->url is the full URL (it might be NULL) */
759:
760: if(!urlnode->url) {
761: /* This node has no URL. Free node data without destroying the
762: node itself nor modifying next pointer and continue to next */
763: Curl_safefree(urlnode->outfile);
764: Curl_safefree(urlnode->infile);
765: urlnode->flags = 0;
766: config->state.urlnode = urlnode->next;
767: state->up = 0;
768: continue; /* next URL please */
769: }
770:
771: /* save outfile pattern before expansion */
772: if(urlnode->outfile && !state->outfiles) {
773: state->outfiles = strdup(urlnode->outfile);
774: if(!state->outfiles) {
775: errorf(global, "out of memory\n");
776: result = CURLE_OUT_OF_MEMORY;
777: break;
778: }
779: }
780:
781: infiles = urlnode->infile;
782:
783: if(!config->globoff && infiles && !inglob) {
784: /* Unless explicitly shut off */
785: result = glob_url(&inglob, infiles, &state->infilenum,
786: global->showerror?global->errors:NULL);
787: if(result)
788: break;
789: config->state.inglob = inglob;
790: }
791:
792: {
793: int separator;
794: unsigned long urlnum;
795:
796: if(!state->up && !infiles)
797: Curl_nop_stmt;
798: else {
799: if(!state->uploadfile) {
800: if(inglob) {
801: result = glob_next_url(&state->uploadfile, inglob);
802: if(result == CURLE_OUT_OF_MEMORY)
803: errorf(global, "out of memory\n");
804: }
805: else if(!state->up) {
806: state->uploadfile = strdup(infiles);
807: if(!state->uploadfile) {
808: errorf(global, "out of memory\n");
809: result = CURLE_OUT_OF_MEMORY;
810: }
811: }
812: }
813: if(result)
814: break;
815: }
816:
817: if(!state->urlnum) {
818: if(metalink) {
819: /* For Metalink download, we don't use glob. Instead we use
820: the number of resources as urlnum. */
821: urlnum = count_next_metalink_resource(mlfile);
822: }
823: else if(!config->globoff) {
824: /* Unless explicitly shut off, we expand '{...}' and '[...]'
825: expressions and return total number of URLs in pattern set */
826: result = glob_url(&state->urls, urlnode->url, &state->urlnum,
827: global->showerror?global->errors:NULL);
828: if(result)
829: break;
830: urlnum = state->urlnum;
831: }
832: else
833: urlnum = 1; /* without globbing, this is a single URL */
834: }
835: else
836: urlnum = state->urlnum;
837:
838: /* if multiple files extracted to stdout, insert separators! */
839: separator = ((!state->outfiles ||
840: !strcmp(state->outfiles, "-")) && urlnum > 1);
841:
842: if(state->up < state->infilenum) {
843: struct per_transfer *per;
844: struct OutStruct *outs;
845: struct InStruct *input;
846: struct OutStruct *heads;
847: struct OutStruct *etag_save;
848: struct HdrCbData *hdrcbdata = NULL;
849: CURL *curl = curl_easy_init();
850: result = add_per_transfer(&per);
851: if(result || !curl) {
852: curl_easy_cleanup(curl);
853: result = CURLE_OUT_OF_MEMORY;
854: break;
855: }
856: if(state->uploadfile) {
857: per->uploadfile = strdup(state->uploadfile);
858: if(!per->uploadfile) {
859: curl_easy_cleanup(curl);
860: result = CURLE_OUT_OF_MEMORY;
861: break;
862: }
863: }
864: *added = TRUE;
865: per->config = config;
866: per->curl = curl;
867:
868: /* default headers output stream is stdout */
869: heads = &per->heads;
870: heads->stream = stdout;
871:
872: /* Single header file for all URLs */
873: if(config->headerfile) {
874: /* open file for output: */
875: if(strcmp(config->headerfile, "-")) {
876: FILE *newfile;
877: newfile = fopen(config->headerfile, per->prev == NULL?"wb":"ab");
878: if(!newfile) {
879: warnf(config->global, "Failed to open %s\n", config->headerfile);
880: result = CURLE_WRITE_ERROR;
881: break;
882: }
883: else {
884: heads->filename = config->headerfile;
885: heads->s_isreg = TRUE;
886: heads->fopened = TRUE;
887: heads->stream = newfile;
888: }
889: }
890: else {
891: /* always use binary mode for protocol header output */
892: set_binmode(heads->stream);
893: }
894: }
895:
896: hdrcbdata = &per->hdrcbdata;
897:
898: outs = &per->outs;
899: input = &per->input;
900:
901: per->outfile = NULL;
902: per->infdopen = FALSE;
903: per->infd = STDIN_FILENO;
904:
905: /* default output stream is stdout */
906: outs->stream = stdout;
907:
908: /* --etag-compare */
909: if(config->etag_compare_file) {
910: char *etag_from_file = NULL;
911: char *header = NULL;
912:
913: /* open file for reading: */
914: FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT);
915: if(!file && !config->etag_save_file) {
916: errorf(config->global,
917: "Failed to open %s\n", config->etag_compare_file);
918: result = CURLE_READ_ERROR;
919: break;
920: }
921:
922: if((PARAM_OK == file2string(&etag_from_file, file)) &&
923: etag_from_file) {
924: header = aprintf("If-None-Match: \"%s\"", etag_from_file);
925: Curl_safefree(etag_from_file);
926: }
927: else
928: header = aprintf("If-None-Match: \"\"");
929:
930: if(!header) {
931: if(file)
932: fclose(file);
933: errorf(config->global,
934: "Failed to allocate memory for custom etag header\n");
935: result = CURLE_OUT_OF_MEMORY;
936: break;
937: }
938:
939: /* add Etag from file to list of custom headers */
940: add2list(&config->headers, header);
941:
942: Curl_safefree(header);
943:
944: if(file) {
945: fclose(file);
946: }
947: }
948:
949: /* --etag-save */
950: etag_save = &per->etag_save;
951: etag_save->stream = stdout;
952:
953: if(config->etag_save_file) {
954: /* open file for output: */
955: if(strcmp(config->etag_save_file, "-")) {
956: FILE *newfile = fopen(config->etag_save_file, "wb");
957: if(!newfile) {
958: warnf(
959: config->global,
960: "Failed to open %s\n", config->etag_save_file);
961:
962: result = CURLE_WRITE_ERROR;
963: break;
964: }
965: else {
966: etag_save->filename = config->etag_save_file;
967: etag_save->s_isreg = TRUE;
968: etag_save->fopened = TRUE;
969: etag_save->stream = newfile;
970: }
971: }
972: else {
973: /* always use binary mode for protocol header output */
974: set_binmode(etag_save->stream);
975: }
976: }
977:
978: if(metalink) {
979: /* For Metalink download, use name in Metalink file as
980: filename. */
981: per->outfile = strdup(mlfile->filename);
982: if(!per->outfile) {
983: result = CURLE_OUT_OF_MEMORY;
984: break;
985: }
986: per->this_url = strdup(mlres->url);
987: if(!per->this_url) {
988: result = CURLE_OUT_OF_MEMORY;
989: break;
990: }
991: per->mlfile = mlfile;
992: }
993: else {
994: if(state->urls) {
995: result = glob_next_url(&per->this_url, state->urls);
996: if(result)
997: break;
998: }
999: else if(!state->li) {
1000: per->this_url = strdup(urlnode->url);
1001: if(!per->this_url) {
1002: result = CURLE_OUT_OF_MEMORY;
1003: break;
1004: }
1005: }
1006: else
1007: per->this_url = NULL;
1008: if(!per->this_url)
1009: break;
1010:
1011: if(state->outfiles) {
1012: per->outfile = strdup(state->outfiles);
1013: if(!per->outfile) {
1014: result = CURLE_OUT_OF_MEMORY;
1015: break;
1016: }
1017: }
1018: }
1019:
1020: if(((urlnode->flags&GETOUT_USEREMOTE) ||
1021: (per->outfile && strcmp("-", per->outfile))) &&
1022: (metalink || !config->use_metalink)) {
1023:
1024: /*
1025: * We have specified a file name to store the result in, or we have
1026: * decided we want to use the remote file name.
1027: */
1028:
1029: if(!per->outfile) {
1030: /* extract the file name from the URL */
1031: result = get_url_file_name(&per->outfile, per->this_url);
1032: if(result)
1033: break;
1034: if(!*per->outfile && !config->content_disposition) {
1035: errorf(global, "Remote file name has no length!\n");
1036: result = CURLE_WRITE_ERROR;
1037: break;
1038: }
1039: }
1040: else if(state->urls) {
1041: /* fill '#1' ... '#9' terms from URL pattern */
1042: char *storefile = per->outfile;
1043: result = glob_match_url(&per->outfile, storefile, state->urls);
1044: Curl_safefree(storefile);
1045: if(result) {
1046: /* bad globbing */
1047: warnf(config->global, "bad output glob!\n");
1048: break;
1049: }
1050: }
1051:
1052: /* Create the directory hierarchy, if not pre-existent to a multiple
1053: file output call */
1054:
1055: if(config->create_dirs || metalink) {
1056: result = create_dir_hierarchy(per->outfile, global->errors);
1057: /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
1058: if(result)
1059: break;
1060: }
1061:
1062: if((urlnode->flags & GETOUT_USEREMOTE)
1063: && config->content_disposition) {
1064: /* Our header callback MIGHT set the filename */
1065: DEBUGASSERT(!outs->filename);
1066: }
1067:
1068: if(config->resume_from || config->resume_from_current) {
1069: #ifdef __VMS
1070: /* open file for output, forcing VMS output format into stream
1071: mode which is needed for stat() call above to always work. */
1072: FILE *file = fopen(outfile, "ab",
1073: "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
1074: #else
1075: /* open file for output: */
1076: FILE *file = fopen(per->outfile, "ab");
1077: #endif
1078: if(!file) {
1079: errorf(global, "Can't open '%s'!\n", per->outfile);
1080: result = CURLE_WRITE_ERROR;
1081: break;
1082: }
1083: outs->fopened = TRUE;
1084: outs->stream = file;
1085:
1086: if(config->resume_from_current) {
1087: /* We're told to continue from where we are now. Get the size
1088: of the file as it is now */
1089: struct_stat fileinfo;
1090: if(0 == fstat(fileno(outs->stream), &fileinfo))
1091: /* set offset to current file size: */
1092: config->resume_from = fileinfo.st_size;
1093: else
1094: /* let offset be 0 */
1095: config->resume_from = 0;
1096: }
1097:
1098: outs->init = config->resume_from;
1099: }
1100: else {
1101: outs->stream = NULL; /* open when needed */
1102: }
1103: outs->filename = per->outfile;
1104: outs->s_isreg = TRUE;
1105: }
1106:
1107: if(per->uploadfile && !stdin_upload(per->uploadfile)) {
1108: /*
1109: * We have specified a file to upload and it isn't "-".
1110: */
1111: char *nurl = add_file_name_to_url(per->this_url, per->uploadfile);
1112: if(!nurl) {
1113: result = CURLE_OUT_OF_MEMORY;
1114: break;
1115: }
1116: per->this_url = nurl;
1117: }
1118: else if(per->uploadfile && stdin_upload(per->uploadfile)) {
1119: /* count to see if there are more than one auth bit set
1120: in the authtype field */
1121: int authbits = 0;
1122: int bitcheck = 0;
1123: while(bitcheck < 32) {
1124: if(config->authtype & (1UL << bitcheck++)) {
1125: authbits++;
1126: if(authbits > 1) {
1127: /* more than one, we're done! */
1128: break;
1129: }
1130: }
1131: }
1132:
1133: /*
1134: * If the user has also selected --anyauth or --proxy-anyauth
1135: * we should warn him/her.
1136: */
1137: if(config->proxyanyauth || (authbits>1)) {
1138: warnf(config->global,
1139: "Using --anyauth or --proxy-anyauth with upload from stdin"
1140: " involves a big risk of it not working. Use a temporary"
1141: " file or a fixed auth type instead!\n");
1142: }
1143:
1144: DEBUGASSERT(per->infdopen == FALSE);
1145: DEBUGASSERT(per->infd == STDIN_FILENO);
1146:
1147: set_binmode(stdin);
1148: if(!strcmp(per->uploadfile, ".")) {
1149: if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0)
1150: warnf(config->global,
1151: "fcntl failed on fd=%d: %s\n", per->infd, strerror(errno));
1152: }
1153: }
1154:
1155: if(per->uploadfile && config->resume_from_current)
1156: config->resume_from = -1; /* -1 will then force get-it-yourself */
1157:
1158: if(output_expected(per->this_url, per->uploadfile) && outs->stream &&
1159: isatty(fileno(outs->stream)))
1160: /* we send the output to a tty, therefore we switch off the progress
1161: meter */
1162: per->noprogress = global->noprogress = global->isatty = TRUE;
1163: else {
1164: /* progress meter is per download, so restore config
1165: values */
1166: per->noprogress = global->noprogress = orig_noprogress;
1167: global->isatty = orig_isatty;
1168: }
1169:
1170: if(urlnum > 1 && !global->mute) {
1171: per->separator_err =
1172: aprintf("\n[%lu/%lu]: %s --> %s",
1173: state->li + 1, urlnum, per->this_url,
1174: per->outfile ? per->outfile : "<stdout>");
1175: if(separator)
1176: per->separator = aprintf("%s%s", CURLseparator, per->this_url);
1177: }
1178: if(httpgetfields) {
1179: char *urlbuffer;
1180: /* Find out whether the url contains a file name */
1181: const char *pc = strstr(per->this_url, "://");
1182: char sep = '?';
1183: if(pc)
1184: pc += 3;
1185: else
1186: pc = per->this_url;
1187:
1188: pc = strrchr(pc, '/'); /* check for a slash */
1189:
1190: if(pc) {
1191: /* there is a slash present in the URL */
1192:
1193: if(strchr(pc, '?'))
1194: /* Ouch, there's already a question mark in the URL string, we
1195: then append the data with an ampersand separator instead! */
1196: sep = '&';
1197: }
1198: /*
1199: * Then append ? followed by the get fields to the url.
1200: */
1201: if(pc)
1202: urlbuffer = aprintf("%s%c%s", per->this_url, sep, httpgetfields);
1203: else
1204: /* Append / before the ? to create a well-formed url
1205: if the url contains a hostname only
1206: */
1207: urlbuffer = aprintf("%s/?%s", per->this_url, httpgetfields);
1208:
1209: if(!urlbuffer) {
1210: result = CURLE_OUT_OF_MEMORY;
1211: break;
1212: }
1213:
1214: Curl_safefree(per->this_url); /* free previous URL */
1215: per->this_url = urlbuffer; /* use our new URL instead! */
1216: }
1217:
1218: if(!global->errors)
1219: global->errors = stderr;
1220:
1221: if((!per->outfile || !strcmp(per->outfile, "-")) &&
1222: !config->use_ascii) {
1223: /* We get the output to stdout and we have not got the ASCII/text
1224: flag, then set stdout to be binary */
1225: set_binmode(stdout);
1226: }
1227:
1228: /* explicitly passed to stdout means okaying binary gunk */
1229: config->terminal_binary_ok =
1230: (per->outfile && !strcmp(per->outfile, "-"));
1231:
1232: /* Avoid having this setopt added to the --libcurl source output. */
1233: result = curl_easy_setopt(curl, CURLOPT_SHARE, share);
1234: if(result)
1235: break;
1236:
1237: if(!config->tcp_nodelay)
1238: my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);
1239:
1240: if(config->tcp_fastopen)
1241: my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
1242:
1243: /* where to store */
1244: my_setopt(curl, CURLOPT_WRITEDATA, per);
1245: my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);
1246:
1247: if(metalink || !config->use_metalink)
1248: /* what call to write */
1249: my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
1250: #ifdef USE_METALINK
1251: else
1252: /* Set Metalink specific write callback function to parse
1253: XML data progressively. */
1254: my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb);
1255: #endif /* USE_METALINK */
1256:
1257: /* for uploads */
1258: input->config = config;
1259: /* Note that if CURLOPT_READFUNCTION is fread (the default), then
1260: * lib/telnet.c will Curl_poll() on the input file descriptor
1261: * rather then calling the READFUNCTION at regular intervals.
1262: * The circumstances in which it is preferable to enable this
1263: * behaviour, by omitting to set the READFUNCTION & READDATA options,
1264: * have not been determined.
1265: */
1266: my_setopt(curl, CURLOPT_READDATA, input);
1267: /* what call to read */
1268: my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
1269:
1270: /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
1271: CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
1272: my_setopt(curl, CURLOPT_SEEKDATA, input);
1273: my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
1274:
1275: if(config->recvpersecond &&
1276: (config->recvpersecond < BUFFER_SIZE))
1277: /* use a smaller sized buffer for better sleeps */
1278: my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond);
1279: else
1280: my_setopt(curl, CURLOPT_BUFFERSIZE, (long)BUFFER_SIZE);
1281:
1282: my_setopt_str(curl, CURLOPT_URL, per->this_url);
1283: my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L);
1284: if(config->no_body)
1285: my_setopt(curl, CURLOPT_NOBODY, 1L);
1286:
1287: if(config->oauth_bearer)
1288: my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
1289:
1290: {
1291: my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
1292: /* new in libcurl 7.5 */
1293: if(config->proxy)
1294: my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
1295:
1296: my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
1297:
1298: /* new in libcurl 7.3 */
1299: my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L);
1300:
1301: /* new in libcurl 7.52.0 */
1302: if(config->preproxy)
1303: my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
1304:
1305: /* new in libcurl 7.10.6 */
1306: if(config->proxyanyauth)
1307: my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
1308: (long)CURLAUTH_ANY);
1309: else if(config->proxynegotiate)
1310: my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
1311: (long)CURLAUTH_GSSNEGOTIATE);
1312: else if(config->proxyntlm)
1313: my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
1314: (long)CURLAUTH_NTLM);
1315: else if(config->proxydigest)
1316: my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
1317: (long)CURLAUTH_DIGEST);
1318: else if(config->proxybasic)
1319: my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
1320: (long)CURLAUTH_BASIC);
1321:
1322: /* new in libcurl 7.19.4 */
1323: my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy);
1324:
1325: my_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS,
1326: config->suppress_connect_headers?1L:0L);
1327: }
1328:
1329: my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L);
1330: my_setopt(curl, CURLOPT_REQUEST_TARGET, config->request_target);
1331: my_setopt(curl, CURLOPT_UPLOAD, per->uploadfile?1L:0L);
1332: my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L);
1333: my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L);
1334:
1335: if(config->netrc_opt)
1336: my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
1337: else if(config->netrc || config->netrc_file)
1338: my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED);
1339: else
1340: my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED);
1341:
1342: if(config->netrc_file)
1343: my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file);
1344:
1345: my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L);
1346: if(config->login_options)
1347: my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options);
1348: my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
1349: my_setopt_str(curl, CURLOPT_RANGE, config->range);
1350: my_setopt(curl, CURLOPT_ERRORBUFFER, per->errorbuffer);
1351: my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000));
1352:
1353: switch(config->httpreq) {
1354: case HTTPREQ_SIMPLEPOST:
1355: my_setopt_str(curl, CURLOPT_POSTFIELDS,
1356: config->postfields);
1357: my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
1358: config->postfieldsize);
1359: break;
1360: case HTTPREQ_MIMEPOST:
1361: /* free previous remainders */
1362: curl_mime_free(config->mimepost);
1363: config->mimepost = NULL;
1364: result = tool2curlmime(curl, config->mimeroot, &config->mimepost);
1365: if(result)
1366: break;
1367: my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost);
1368: break;
1369: default:
1370: break;
1371: }
1372: if(result)
1373: break;
1374:
1375: /* new in libcurl 7.10.6 (default is Basic) */
1376: if(config->authtype)
1377: my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype);
1378:
1379: my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
1380:
1381: if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) {
1382: my_setopt_str(curl, CURLOPT_REFERER, config->referer);
1383: my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
1384: }
1385:
1386: if(built_in_protos & CURLPROTO_HTTP) {
1387:
1388: long postRedir = 0;
1389:
1390: my_setopt(curl, CURLOPT_FOLLOWLOCATION,
1391: config->followlocation?1L:0L);
1392: my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
1393: config->unrestricted_auth?1L:0L);
1394:
1395: my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L);
1396:
1397: /* new in libcurl 7.36.0 */
1398: if(config->proxyheaders) {
1399: my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders);
1400: my_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
1401: }
1402:
1403: /* new in libcurl 7.5 */
1404: my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
1405:
1406: if(config->httpversion)
1407: my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
1408: else if(curlinfo->features & CURL_VERSION_HTTP2) {
1409: my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
1410: }
1411:
1412: /* curl 7.19.1 (the 301 version existed in 7.18.2),
1413: 303 was added in 7.26.0 */
1414: if(config->post301)
1415: postRedir |= CURL_REDIR_POST_301;
1416: if(config->post302)
1417: postRedir |= CURL_REDIR_POST_302;
1418: if(config->post303)
1419: postRedir |= CURL_REDIR_POST_303;
1420: my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
1421:
1422: /* new in libcurl 7.21.6 */
1423: if(config->encoding)
1424: my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
1425:
1426: /* new in libcurl 7.21.6 */
1427: if(config->tr_encoding)
1428: my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
1429: /* new in libcurl 7.64.0 */
1430: my_setopt(curl, CURLOPT_HTTP09_ALLOWED,
1431: config->http09_allowed ? 1L : 0L);
1432:
1433: } /* (built_in_protos & CURLPROTO_HTTP) */
1434:
1435: my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
1436: my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
1437: config->low_speed_limit);
1438: my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
1439: my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
1440: config->sendpersecond);
1441: my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
1442: config->recvpersecond);
1443:
1444: if(config->use_resume)
1445: my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from);
1446: else
1447: my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
1448:
1449: my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
1450: my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
1451:
1452: if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
1453:
1454: /* SSH and SSL private key uses same command-line option */
1455: /* new in libcurl 7.16.1 */
1456: my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
1457: /* new in libcurl 7.16.1 */
1458: my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
1459:
1460: /* new in libcurl 7.17.1: SSH host key md5 checking allows us
1461: to fail if we are not talking to who we think we should */
1462: my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
1463: config->hostpubmd5);
1464:
1465: /* new in libcurl 7.56.0 */
1466: if(config->ssh_compression)
1467: my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
1468: }
1469:
1470: if(config->cacert)
1471: my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
1472: if(config->proxy_cacert)
1473: my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
1474:
1475: if(config->capath) {
1476: result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
1477: if(result == CURLE_NOT_BUILT_IN) {
1478: warnf(config->global, "ignoring %s, not supported by libcurl\n",
1479: capath_from_env?
1480: "SSL_CERT_DIR environment variable":"--capath");
1481: }
1482: else if(result)
1483: break;
1484: }
1485: /* For the time being if --proxy-capath is not set then we use the
1486: --capath value for it, if any. See #1257 */
1487: if((config->proxy_capath || config->capath) &&
1488: !tool_setopt_skip(CURLOPT_PROXY_CAPATH)) {
1489: result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH,
1490: (config->proxy_capath ?
1491: config->proxy_capath :
1492: config->capath));
1493: if(result == CURLE_NOT_BUILT_IN) {
1494: if(config->proxy_capath) {
1495: warnf(config->global,
1496: "ignoring --proxy-capath, not supported by libcurl\n");
1497: }
1498: }
1499: else if(result)
1500: break;
1501: }
1502:
1503: if(config->crlfile)
1504: my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
1505: if(config->proxy_crlfile)
1506: my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
1507: else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
1508: my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
1509:
1510: if(config->pinnedpubkey)
1511: my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
1512:
1513: if(curlinfo->features & CURL_VERSION_SSL) {
1514: /* Check if config->cert is a PKCS#11 URI and set the
1515: * config->cert_type if necessary */
1516: if(config->cert) {
1517: if(!config->cert_type) {
1518: if(is_pkcs11_uri(config->cert)) {
1519: config->cert_type = strdup("ENG");
1520: }
1521: }
1522: }
1523:
1524: /* Check if config->key is a PKCS#11 URI and set the
1525: * config->key_type if necessary */
1526: if(config->key) {
1527: if(!config->key_type) {
1528: if(is_pkcs11_uri(config->key)) {
1529: config->key_type = strdup("ENG");
1530: }
1531: }
1532: }
1533:
1534: /* Check if config->proxy_cert is a PKCS#11 URI and set the
1535: * config->proxy_type if necessary */
1536: if(config->proxy_cert) {
1537: if(!config->proxy_cert_type) {
1538: if(is_pkcs11_uri(config->proxy_cert)) {
1539: config->proxy_cert_type = strdup("ENG");
1540: }
1541: }
1542: }
1543:
1544: /* Check if config->proxy_key is a PKCS#11 URI and set the
1545: * config->proxy_key_type if necessary */
1546: if(config->proxy_key) {
1547: if(!config->proxy_key_type) {
1548: if(is_pkcs11_uri(config->proxy_key)) {
1549: config->proxy_key_type = strdup("ENG");
1550: }
1551: }
1552: }
1553:
1554: my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
1555: my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
1556: my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
1557: my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
1558: config->proxy_cert_type);
1559: my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
1560: my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
1561: my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
1562: my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
1563: config->proxy_key_type);
1564:
1565: if(config->insecure_ok) {
1566: my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1567: my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1568: }
1569: else {
1570: my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
1571: /* libcurl default is strict verifyhost -> 2L */
1572: /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
1573: }
1574: if(config->proxy_insecure_ok) {
1575: my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
1576: my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
1577: }
1578: else {
1579: my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
1580: }
1581:
1582: if(config->verifystatus)
1583: my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
1584:
1585: if(config->falsestart)
1586: my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
1587:
1588: my_setopt_enum(curl, CURLOPT_SSLVERSION,
1589: config->ssl_version | config->ssl_version_max);
1590: my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
1591: config->proxy_ssl_version);
1592: }
1593: if(config->path_as_is)
1594: my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
1595:
1596: if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
1597: if(!config->insecure_ok) {
1598: char *home;
1599: char *file;
1600: result = CURLE_FAILED_INIT;
1601: home = homedir();
1602: if(home) {
1603: file = aprintf("%s/.ssh/known_hosts", home);
1604: if(file) {
1605: /* new in curl 7.19.6 */
1606: result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
1607: curl_free(file);
1608: if(result == CURLE_UNKNOWN_OPTION)
1609: /* libssh2 version older than 1.1.1 */
1610: result = CURLE_OK;
1611: }
1612: Curl_safefree(home);
1613: }
1614: else {
1615: errorf(global, "Failed to figure out user's home dir!");
1616: }
1617: if(result)
1618: break;
1619: }
1620: }
1621:
1622: if(config->no_body || config->remote_time) {
1623: /* no body or use remote time */
1624: my_setopt(curl, CURLOPT_FILETIME, 1L);
1625: }
1626:
1627: my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L);
1628: my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
1629: my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
1630: my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
1631:
1632: if(config->cookie)
1633: my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
1634:
1635: if(config->cookiefile)
1636: my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
1637:
1638: /* new in libcurl 7.9 */
1639: if(config->cookiejar)
1640: my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
1641:
1642: /* new in libcurl 7.9.7 */
1643: my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L);
1644:
1645: my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond);
1646: my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
1647: my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
1648: customrequest_helper(config, config->httpreq, config->customrequest);
1649: my_setopt(curl, CURLOPT_STDERR, global->errors);
1650:
1651: /* three new ones in libcurl 7.3: */
1652: my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
1653: my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
1654: progressbarinit(&per->progressbar, config);
1655:
1656: if((global->progressmode == CURL_PROGRESS_BAR) &&
1657: !global->noprogress && !global->mute) {
1658: /* we want the alternative style, then we have to implement it
1659: ourselves! */
1660: my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
1661: my_setopt(curl, CURLOPT_XFERINFODATA, per);
1662: }
1663: else if(per->uploadfile && !strcmp(per->uploadfile, ".")) {
1664: /* when reading from stdin in non-blocking mode, we use the progress
1665: function to unpause a busy read */
1666: my_setopt(curl, CURLOPT_NOPROGRESS, 0L);
1667: my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb);
1668: my_setopt(curl, CURLOPT_XFERINFODATA, per);
1669: }
1670:
1671: /* new in libcurl 7.24.0: */
1672: if(config->dns_servers)
1673: my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
1674:
1675: /* new in libcurl 7.33.0: */
1676: if(config->dns_interface)
1677: my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);
1678: if(config->dns_ipv4_addr)
1679: my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr);
1680: if(config->dns_ipv6_addr)
1681: my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr);
1682:
1683: /* new in libcurl 7.6.2: */
1684: my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
1685:
1686: /* new in libcurl 7.7: */
1687: my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
1688: my_setopt_str(curl, CURLOPT_EGDSOCKET, config->egd_file);
1689: my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS,
1690: (long)(config->connecttimeout * 1000));
1691:
1692: if(config->doh_url)
1693: my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url);
1694:
1695: if(config->cipher_list)
1696: my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
1697:
1698: if(config->proxy_cipher_list)
1699: my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
1700: config->proxy_cipher_list);
1701:
1702: if(config->cipher13_list)
1703: my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, config->cipher13_list);
1704:
1705: if(config->proxy_cipher13_list)
1706: my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS,
1707: config->proxy_cipher13_list);
1708:
1709: /* new in libcurl 7.9.2: */
1710: if(config->disable_epsv)
1711: /* disable it */
1712: my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
1713:
1714: /* new in libcurl 7.10.5 */
1715: if(config->disable_eprt)
1716: /* disable it */
1717: my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L);
1718:
1719: if(global->tracetype != TRACE_NONE) {
1720: my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
1721: my_setopt(curl, CURLOPT_DEBUGDATA, config);
1722: my_setopt(curl, CURLOPT_VERBOSE, 1L);
1723: }
1724:
1725: /* new in curl 7.9.3 */
1726: if(config->engine) {
1727: result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
1728: if(result)
1729: break;
1730: }
1731:
1732: /* new in curl 7.10.7, extended in 7.19.4. Modified to use
1733: CREATE_DIR_RETRY in 7.49.0 */
1734: my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
1735: (long)(config->ftp_create_dirs?
1736: CURLFTP_CREATE_DIR_RETRY:
1737: CURLFTP_CREATE_DIR_NONE));
1738:
1739: /* new in curl 7.10.8 */
1740: if(config->max_filesize)
1741: my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
1742: config->max_filesize);
1743:
1744: if(4 == config->ip_version)
1745: my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1746: else if(6 == config->ip_version)
1747: my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
1748: else
1749: my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
1750:
1751: /* new in curl 7.15.5 */
1752: if(config->ftp_ssl_reqd)
1753: my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
1754:
1755: /* new in curl 7.11.0 */
1756: else if(config->ftp_ssl)
1757: my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
1758:
1759: /* new in curl 7.16.0 */
1760: else if(config->ftp_ssl_control)
1761: my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL);
1762:
1763: /* new in curl 7.16.1 */
1764: if(config->ftp_ssl_ccc)
1765: my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC,
1766: (long)config->ftp_ssl_ccc_mode);
1767:
1768: /* new in curl 7.19.4 */
1769: if(config->socks5_gssapi_nec)
1770: my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
1771: config->socks5_gssapi_nec);
1772:
1773: /* new in curl 7.55.0 */
1774: if(config->socks5_auth)
1775: my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH,
1776: (long)config->socks5_auth);
1777:
1778: /* new in curl 7.43.0 */
1779: if(config->proxy_service_name)
1780: my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME,
1781: config->proxy_service_name);
1782:
1783: /* new in curl 7.43.0 */
1784: if(config->service_name)
1785: my_setopt_str(curl, CURLOPT_SERVICE_NAME,
1786: config->service_name);
1787:
1788: /* curl 7.13.0 */
1789: my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
1790: my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L);
1791:
1792: /* curl 7.14.2 */
1793: my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
1794:
1795: /* curl 7.15.1 */
1796: my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod);
1797:
1798: /* curl 7.15.2 */
1799: if(config->localport) {
1800: my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
1801: my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, config->localportrange);
1802: }
1803:
1804: /* curl 7.15.5 */
1805: my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
1806: config->ftp_alternative_to_user);
1807:
1808: /* curl 7.16.0 */
1809: if(config->disable_sessionid)
1810: /* disable it */
1811: my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
1812:
1813: /* curl 7.16.2 */
1814: if(config->raw) {
1815: my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
1816: my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
1817: }
1818:
1819: /* curl 7.17.1 */
1820: if(!config->nokeepalive) {
1821: my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
1822: if(config->alivetime != 0) {
1823: my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
1824: my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
1825: }
1826: }
1827: else
1828: my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
1829:
1830: /* curl 7.20.0 */
1831: if(config->tftp_blksize)
1832: my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
1833:
1834: if(config->mail_from)
1835: my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
1836:
1837: if(config->mail_rcpt)
1838: my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
1839:
1840: /* curl 7.69.x */
1841: my_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS,
1842: config->mail_rcpt_allowfails ? 1L : 0L);
1843:
1844: /* curl 7.20.x */
1845: if(config->ftp_pret)
1846: my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);
1847:
1848: if(config->proto_present)
1849: my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
1850: if(config->proto_redir_present)
1851: my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
1852:
1853: if(config->content_disposition
1854: && (urlnode->flags & GETOUT_USEREMOTE))
1855: hdrcbdata->honor_cd_filename = TRUE;
1856: else
1857: hdrcbdata->honor_cd_filename = FALSE;
1858:
1859: hdrcbdata->outs = outs;
1860: hdrcbdata->heads = heads;
1861: hdrcbdata->etag_save = etag_save;
1862: hdrcbdata->global = global;
1863: hdrcbdata->config = config;
1864:
1865: my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
1866: my_setopt(curl, CURLOPT_HEADERDATA, per);
1867:
1868: if(config->resolve)
1869: /* new in 7.21.3 */
1870: my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
1871:
1872: if(config->connect_to)
1873: /* new in 7.49.0 */
1874: my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
1875:
1876: /* new in 7.21.4 */
1877: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
1878: if(config->tls_username)
1879: my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
1880: config->tls_username);
1881: if(config->tls_password)
1882: my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
1883: config->tls_password);
1884: if(config->tls_authtype)
1885: my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
1886: config->tls_authtype);
1887: if(config->proxy_tls_username)
1888: my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
1889: config->proxy_tls_username);
1890: if(config->proxy_tls_password)
1891: my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
1892: config->proxy_tls_password);
1893: if(config->proxy_tls_authtype)
1894: my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
1895: config->proxy_tls_authtype);
1896: }
1897:
1898: /* new in 7.22.0 */
1899: if(config->gssapi_delegation)
1900: my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
1901: config->gssapi_delegation);
1902:
1903: /* new in 7.25.0, 7.44.0 and 7.70.0 */
1904: {
1905: long mask = (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
1906: (config->ssl_revoke_best_effort ?
1907: CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
1908: (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0);
1909: if(mask)
1910: my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
1911: }
1912:
1913: if(config->proxy_ssl_allow_beast)
1914: my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS,
1915: (long)CURLSSLOPT_ALLOW_BEAST);
1916:
1917: if(config->mail_auth)
1918: my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
1919:
1920: /* new in 7.66.0 */
1921: if(config->sasl_authzid)
1922: my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid);
1923:
1924: /* new in 7.31.0 */
1925: if(config->sasl_ir)
1926: my_setopt(curl, CURLOPT_SASL_IR, 1L);
1927:
1928: if(config->nonpn) {
1929: my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L);
1930: }
1931:
1932: if(config->noalpn) {
1933: my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
1934: }
1935:
1936: /* new in 7.40.0, abstract support added in 7.53.0 */
1937: if(config->unix_socket_path) {
1938: if(config->abstract_unix_socket) {
1939: my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
1940: config->unix_socket_path);
1941: }
1942: else {
1943: my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
1944: config->unix_socket_path);
1945: }
1946: }
1947:
1948: /* new in 7.45.0 */
1949: if(config->proto_default)
1950: my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
1951:
1952: /* new in 7.47.0 */
1953: if(config->expect100timeout > 0)
1954: my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS,
1955: (long)(config->expect100timeout*1000));
1956:
1957: /* new in 7.48.0 */
1958: if(config->tftp_no_options)
1959: my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
1960:
1961: /* new in 7.59.0 */
1962: if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT)
1963: my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
1964: config->happy_eyeballs_timeout_ms);
1965:
1966: /* new in 7.60.0 */
1967: if(config->haproxy_protocol)
1968: my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
1969:
1970: if(config->disallow_username_in_url)
1971: my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L);
1972:
1973: if(config->altsvc)
1974: my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc);
1975:
1976: #ifdef USE_METALINK
1977: if(!metalink && config->use_metalink) {
1978: outs->metalink_parser = metalink_parser_context_new();
1979: if(outs->metalink_parser == NULL) {
1980: result = CURLE_OUT_OF_MEMORY;
1981: break;
1982: }
1983: fprintf(config->global->errors,
1984: "Metalink: parsing (%s) metalink/XML...\n", per->this_url);
1985: }
1986: else if(metalink)
1987: fprintf(config->global->errors,
1988: "Metalink: fetching (%s) from (%s)...\n",
1989: mlfile->filename, per->this_url);
1990: #endif /* USE_METALINK */
1991:
1992: per->metalink = metalink;
1993: /* initialize retry vars for loop below */
1994: per->retry_sleep_default = (config->retry_delay) ?
1995: config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
1996: per->retry_numretries = config->req_retry;
1997: per->retry_sleep = per->retry_sleep_default; /* ms */
1998: per->retrystart = tvnow();
1999:
2000: state->li++;
2001: /* Here's looping around each globbed URL */
2002: if(state->li >= urlnum) {
2003: state->li = 0;
2004: state->urlnum = 0; /* forced reglob of URLs */
2005: glob_cleanup(state->urls);
2006: state->urls = NULL;
2007: state->up++;
2008: Curl_safefree(state->uploadfile); /* clear it to get the next */
2009: }
2010: }
2011: else {
2012: /* Free this URL node data without destroying the
2013: the node itself nor modifying next pointer. */
2014: Curl_safefree(urlnode->outfile);
2015: Curl_safefree(urlnode->infile);
2016: urlnode->flags = 0;
2017: glob_cleanup(state->urls);
2018: state->urls = NULL;
2019: state->urlnum = 0;
2020:
2021: Curl_safefree(state->outfiles);
2022: Curl_safefree(state->uploadfile);
2023: if(state->inglob) {
2024: /* Free list of globbed upload files */
2025: glob_cleanup(state->inglob);
2026: state->inglob = NULL;
2027: }
2028: config->state.urlnode = urlnode->next;
2029: state->up = 0;
2030: continue;
2031: }
2032: }
2033: break;
2034: }
2035:
2036: if(!*added || result) {
2037: *added = FALSE;
2038: single_transfer_cleanup(config);
2039: }
2040: return result;
2041: }
2042:
2043: static long all_added; /* number of easy handles currently added */
2044:
2045: /*
2046: * add_parallel_transfers() sets 'morep' to TRUE if there are more transfers
2047: * to add even after this call returns. sets 'addedp' to TRUE if one or more
2048: * transfers were added.
2049: */
2050: static CURLcode add_parallel_transfers(struct GlobalConfig *global,
2051: CURLM *multi,
2052: CURLSH *share,
2053: bool *morep,
2054: bool *addedp)
2055: {
2056: struct per_transfer *per;
2057: CURLcode result = CURLE_OK;
2058: CURLMcode mcode;
2059: *addedp = FALSE;
2060: *morep = FALSE;
2061: result = create_transfer(global, share, addedp);
2062: if(result)
2063: return result;
2064: for(per = transfers; per && (all_added < global->parallel_max);
2065: per = per->next) {
2066: bool getadded = FALSE;
2067: if(per->added)
2068: /* already added */
2069: continue;
2070:
2071: result = pre_transfer(global, per);
2072: if(result)
2073: break;
2074:
2075: /* parallel connect means that we don't set PIPEWAIT since pipewait
2076: will make libcurl prefer multiplexing */
2077: (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
2078: global->parallel_connect ? 0L : 1L);
2079: (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
2080: (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
2081: (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
2082:
2083: mcode = curl_multi_add_handle(multi, per->curl);
2084: if(mcode)
2085: return CURLE_OUT_OF_MEMORY;
2086:
2087: result = create_transfer(global, share, &getadded);
2088: if(result)
2089: return result;
2090: per->added = TRUE;
2091: all_added++;
2092: *addedp = TRUE;
2093: }
2094: *morep = per ? TRUE : FALSE;
2095: return CURLE_OK;
2096: }
2097:
2098: static CURLcode parallel_transfers(struct GlobalConfig *global,
2099: CURLSH *share)
2100: {
2101: CURLM *multi;
2102: CURLMcode mcode = CURLM_OK;
2103: CURLcode result = CURLE_OK;
2104: int still_running = 1;
2105: struct timeval start = tvnow();
2106: bool more_transfers;
2107: bool added_transfers;
2108:
2109: multi = curl_multi_init();
2110: if(!multi)
2111: return CURLE_OUT_OF_MEMORY;
2112:
2113: result = add_parallel_transfers(global, multi, share,
2114: &more_transfers, &added_transfers);
2115: if(result) {
2116: curl_multi_cleanup(multi);
2117: return result;
2118: }
2119:
2120: while(!mcode && (still_running || more_transfers)) {
2121: mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
2122: if(!mcode)
2123: mcode = curl_multi_perform(multi, &still_running);
2124:
2125: progress_meter(global, &start, FALSE);
2126:
2127: if(!mcode) {
2128: int rc;
2129: CURLMsg *msg;
2130: bool removed = FALSE;
2131: do {
2132: msg = curl_multi_info_read(multi, &rc);
2133: if(msg) {
2134: bool retry;
2135: struct per_transfer *ended;
2136: CURL *easy = msg->easy_handle;
2137: result = msg->data.result;
2138: curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended);
2139: curl_multi_remove_handle(multi, easy);
2140:
2141: result = post_per_transfer(global, ended, result, &retry);
2142: if(retry)
2143: continue;
2144: progress_finalize(ended); /* before it goes away */
2145: all_added--; /* one fewer added */
2146: removed = TRUE;
2147: (void)del_per_transfer(ended);
2148: }
2149: } while(msg);
2150: if(removed) {
2151: /* one or more transfers completed, add more! */
2152: (void)add_parallel_transfers(global, multi, share,
2153: &more_transfers,
2154: &added_transfers);
2155: if(added_transfers)
2156: /* we added new ones, make sure the loop doesn't exit yet */
2157: still_running = 1;
2158: }
2159: }
2160: }
2161:
2162: (void)progress_meter(global, &start, TRUE);
2163:
2164: /* Make sure to return some kind of error if there was a multi problem */
2165: if(mcode) {
2166: result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
2167: /* The other multi errors should never happen, so return
2168: something suitably generic */
2169: CURLE_BAD_FUNCTION_ARGUMENT;
2170: }
2171:
2172: curl_multi_cleanup(multi);
2173:
2174: return result;
2175: }
2176:
2177: static CURLcode serial_transfers(struct GlobalConfig *global,
2178: CURLSH *share)
2179: {
2180: CURLcode returncode = CURLE_OK;
2181: CURLcode result = CURLE_OK;
2182: struct per_transfer *per;
2183: bool added = FALSE;
2184:
2185: result = create_transfer(global, share, &added);
2186: if(result || !added)
2187: return result;
2188: for(per = transfers; per;) {
2189: bool retry;
2190: bool bailout = FALSE;
2191: result = pre_transfer(global, per);
2192: if(result)
2193: break;
2194:
2195: #ifndef CURL_DISABLE_LIBCURL_OPTION
2196: if(global->libcurl) {
2197: result = easysrc_perform();
2198: if(result)
2199: break;
2200: }
2201: #endif
2202: #ifdef CURLDEBUG
2203: if(global->test_event_based)
2204: result = curl_easy_perform_ev(per->curl);
2205: else
2206: #endif
2207: result = curl_easy_perform(per->curl);
2208:
2209: /* store the result of the actual transfer */
2210: returncode = result;
2211:
2212: result = post_per_transfer(global, per, result, &retry);
2213: if(retry)
2214: continue;
2215:
2216: /* Bail out upon critical errors or --fail-early */
2217: if(result || is_fatal_error(returncode) ||
2218: (returncode && global->fail_early))
2219: bailout = TRUE;
2220: else {
2221: /* setup the next one just before we delete this */
2222: result = create_transfer(global, share, &added);
2223: if(result)
2224: bailout = TRUE;
2225: }
2226:
2227: /* Release metalink related resources here */
2228: delete_metalinkfile(per->mlfile);
2229:
2230: per = del_per_transfer(per);
2231:
2232: if(bailout)
2233: break;
2234: }
2235: if(returncode)
2236: /* returncode errors have priority */
2237: result = returncode;
2238:
2239: if(result)
2240: single_transfer_cleanup(global->current);
2241:
2242: return result;
2243: }
2244:
2245: /* setup a transfer for the given config */
2246: static CURLcode transfer_per_config(struct GlobalConfig *global,
2247: struct OperationConfig *config,
2248: CURLSH *share,
2249: bool *added)
2250: {
2251: CURLcode result = CURLE_OK;
2252: bool capath_from_env;
2253: *added = FALSE;
2254:
2255: /* Check we have a url */
2256: if(!config->url_list || !config->url_list->url) {
2257: helpf(global->errors, "no URL specified!\n");
2258: return CURLE_FAILED_INIT;
2259: }
2260:
2261: /* On WIN32 we can't set the path to curl-ca-bundle.crt
2262: * at compile time. So we look here for the file in two ways:
2263: * 1: look at the environment variable CURL_CA_BUNDLE for a path
2264: * 2: if #1 isn't found, use the windows API function SearchPath()
2265: * to find it along the app's path (includes app's dir and CWD)
2266: *
2267: * We support the environment variable thing for non-Windows platforms
2268: * too. Just for the sake of it.
2269: */
2270: capath_from_env = false;
2271: if(!config->cacert &&
2272: !config->capath &&
2273: !config->insecure_ok) {
2274: CURL *curltls = curl_easy_init();
2275: struct curl_tlssessioninfo *tls_backend_info = NULL;
2276:
2277: /* With the addition of CAINFO support for Schannel, this search could find
2278: * a certificate bundle that was previously ignored. To maintain backward
2279: * compatibility, only perform this search if not using Schannel.
2280: */
2281: result = curl_easy_getinfo(curltls, CURLINFO_TLS_SSL_PTR,
2282: &tls_backend_info);
2283: if(result)
2284: return result;
2285:
2286: /* Set the CA cert locations specified in the environment. For Windows if
2287: * no environment-specified filename is found then check for CA bundle
2288: * default filename curl-ca-bundle.crt in the user's PATH.
2289: *
2290: * If Schannel is the selected SSL backend then these locations are
2291: * ignored. We allow setting CA location for schannel only when explicitly
2292: * specified by the user via CURLOPT_CAINFO / --cacert.
2293: */
2294: if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) {
2295: char *env;
2296: env = curlx_getenv("CURL_CA_BUNDLE");
2297: if(env) {
2298: config->cacert = strdup(env);
2299: if(!config->cacert) {
2300: curl_free(env);
2301: errorf(global, "out of memory\n");
2302: return CURLE_OUT_OF_MEMORY;
2303: }
2304: }
2305: else {
2306: env = curlx_getenv("SSL_CERT_DIR");
2307: if(env) {
2308: config->capath = strdup(env);
2309: if(!config->capath) {
2310: curl_free(env);
2311: helpf(global->errors, "out of memory\n");
2312: return CURLE_OUT_OF_MEMORY;
2313: }
2314: capath_from_env = true;
2315: }
2316: else {
2317: env = curlx_getenv("SSL_CERT_FILE");
2318: if(env) {
2319: config->cacert = strdup(env);
2320: if(!config->cacert) {
2321: curl_free(env);
2322: errorf(global, "out of memory\n");
2323: return CURLE_OUT_OF_MEMORY;
2324: }
2325: }
2326: }
2327: }
2328:
2329: if(env)
2330: curl_free(env);
2331: #ifdef WIN32
2332: else {
2333: result = FindWin32CACert(config, tls_backend_info->backend,
2334: "curl-ca-bundle.crt");
2335: }
2336: #endif
2337: }
2338: curl_easy_cleanup(curltls);
2339: }
2340:
2341: if(!result)
2342: result = single_transfer(global, config, share, capath_from_env, added);
2343:
2344: return result;
2345: }
2346:
2347: /*
2348: * 'create_transfer' gets the details and sets up a new transfer if 'added'
2349: * returns TRUE.
2350: */
2351: static CURLcode create_transfer(struct GlobalConfig *global,
2352: CURLSH *share,
2353: bool *added)
2354: {
2355: CURLcode result = CURLE_OK;
2356: *added = FALSE;
2357: while(global->current) {
2358: result = transfer_per_config(global, global->current, share, added);
2359: if(!result && !*added) {
2360: /* when one set is drained, continue to next */
2361: global->current = global->current->next;
2362: continue;
2363: }
2364: break;
2365: }
2366: return result;
2367: }
2368:
2369: static CURLcode run_all_transfers(struct GlobalConfig *global,
2370: CURLSH *share,
2371: CURLcode result)
2372: {
2373: /* Save the values of noprogress and isatty to restore them later on */
2374: bool orig_noprogress = global->noprogress;
2375: bool orig_isatty = global->isatty;
2376: struct per_transfer *per;
2377:
2378: /* Time to actually do the transfers */
2379: if(!result) {
2380: if(global->parallel)
2381: result = parallel_transfers(global, share);
2382: else
2383: result = serial_transfers(global, share);
2384: }
2385:
2386: /* cleanup if there are any left */
2387: for(per = transfers; per;) {
2388: bool retry;
2389: CURLcode result2 = post_per_transfer(global, per, result, &retry);
2390: if(!result)
2391: /* don't overwrite the original error */
2392: result = result2;
2393:
2394: /* Free list of given URLs */
2395: clean_getout(per->config);
2396:
2397: /* Release metalink related resources here */
2398: clean_metalink(per->config);
2399: per = del_per_transfer(per);
2400: }
2401:
2402: /* Reset the global config variables */
2403: global->noprogress = orig_noprogress;
2404: global->isatty = orig_isatty;
2405:
2406:
2407: return result;
2408: }
2409:
2410: CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
2411: {
2412: CURLcode result = CURLE_OK;
2413:
2414: /* Setup proper locale from environment */
2415: #ifdef HAVE_SETLOCALE
2416: setlocale(LC_ALL, "");
2417: #endif
2418:
2419: /* Parse .curlrc if necessary */
2420: if((argc == 1) ||
2421: (!curl_strequal(argv[1], "-q") &&
2422: !curl_strequal(argv[1], "--disable"))) {
2423: parseconfig(NULL, global); /* ignore possible failure */
2424:
2425: /* If we had no arguments then make sure a url was specified in .curlrc */
2426: if((argc < 2) && (!global->first->url_list)) {
2427: helpf(global->errors, NULL);
2428: result = CURLE_FAILED_INIT;
2429: }
2430: }
2431:
2432: if(!result) {
2433: /* Parse the command line arguments */
2434: ParameterError res = parse_args(global, argc, argv);
2435: if(res) {
2436: result = CURLE_OK;
2437:
2438: /* Check if we were asked for the help */
2439: if(res == PARAM_HELP_REQUESTED)
2440: tool_help();
2441: /* Check if we were asked for the manual */
2442: else if(res == PARAM_MANUAL_REQUESTED)
2443: hugehelp();
2444: /* Check if we were asked for the version information */
2445: else if(res == PARAM_VERSION_INFO_REQUESTED)
2446: tool_version_info();
2447: /* Check if we were asked to list the SSL engines */
2448: else if(res == PARAM_ENGINES_REQUESTED)
2449: tool_list_engines();
2450: else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
2451: result = CURLE_UNSUPPORTED_PROTOCOL;
2452: else
2453: result = CURLE_FAILED_INIT;
2454: }
2455: else {
2456: #ifndef CURL_DISABLE_LIBCURL_OPTION
2457: if(global->libcurl) {
2458: /* Initialise the libcurl source output */
2459: result = easysrc_init();
2460: }
2461: #endif
2462:
2463: /* Perform the main operations */
2464: if(!result) {
2465: size_t count = 0;
2466: struct OperationConfig *operation = global->first;
2467: CURLSH *share = curl_share_init();
2468: if(!share) {
2469: #ifndef CURL_DISABLE_LIBCURL_OPTION
2470: if(global->libcurl) {
2471: /* Cleanup the libcurl source output */
2472: easysrc_cleanup();
2473: }
2474: #endif
2475: return CURLE_OUT_OF_MEMORY;
2476: }
2477:
2478: curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
2479: curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
2480: curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
2481: curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
2482: curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL);
2483:
2484: /* Get the required arguments for each operation */
2485: do {
2486: result = get_args(operation, count++);
2487:
2488: operation = operation->next;
2489: } while(!result && operation);
2490:
2491: /* Set the current operation pointer */
2492: global->current = global->first;
2493:
2494: /* now run! */
2495: result = run_all_transfers(global, share, result);
2496:
2497: curl_share_cleanup(share);
2498: #ifndef CURL_DISABLE_LIBCURL_OPTION
2499: if(global->libcurl) {
2500: /* Cleanup the libcurl source output */
2501: easysrc_cleanup();
2502:
2503: /* Dump the libcurl code if previously enabled */
2504: dumpeasysrc(global);
2505: }
2506: #endif
2507: }
2508: else
2509: errorf(global, "out of memory\n");
2510: }
2511: }
2512:
2513: return result;
2514: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>