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 #include "tool_operate.h"
26
27 #include "strcase.h"
28
29 #define ENABLE_CURLX_PRINTF
30 /* use our own printf() functions */
31 #include "curlx.h"
32
33 #include "tool_cfgable.h"
34 #include "tool_doswin.h"
35 #include "tool_operhlp.h"
36
37 #include "memdebug.h" /* keep this as LAST include */
38
clean_getout(struct OperationConfig * config)39 void clean_getout(struct OperationConfig *config)
40 {
41 if(config) {
42 struct getout *next;
43 struct getout *node = config->url_list;
44
45 while(node) {
46 next = node->next;
47 Curl_safefree(node->url);
48 Curl_safefree(node->outfile);
49 Curl_safefree(node->infile);
50 Curl_safefree(node);
51 node = next;
52 }
53 config->url_list = NULL;
54 }
55 single_transfer_cleanup(config);
56 }
57
output_expected(const char * url,const char * uploadfile)58 bool output_expected(const char *url, const char *uploadfile)
59 {
60 if(!uploadfile)
61 return TRUE; /* download */
62 if(checkprefix("http://", url) || checkprefix("https://", url))
63 return TRUE; /* HTTP(S) upload */
64
65 return FALSE; /* non-HTTP upload, probably no output should be expected */
66 }
67
stdin_upload(const char * uploadfile)68 bool stdin_upload(const char *uploadfile)
69 {
70 return (!strcmp(uploadfile, "-") ||
71 !strcmp(uploadfile, ".")) ? TRUE : FALSE;
72 }
73
74 /* Convert a CURLUcode into a CURLcode */
urlerr_cvt(CURLUcode ucode)75 CURLcode urlerr_cvt(CURLUcode ucode)
76 {
77 if(ucode == CURLUE_OUT_OF_MEMORY)
78 return CURLE_OUT_OF_MEMORY;
79 else if(ucode == CURLUE_UNSUPPORTED_SCHEME)
80 return CURLE_UNSUPPORTED_PROTOCOL;
81 else if(ucode == CURLUE_LACKS_IDN)
82 return CURLE_NOT_BUILT_IN;
83 else if(ucode == CURLUE_BAD_HANDLE)
84 return CURLE_BAD_FUNCTION_ARGUMENT;
85 return CURLE_URL_MALFORMAT;
86 }
87
88 /*
89 * Adds the file name to the URL if it doesn't already have one.
90 * url will be freed before return if the returned pointer is different
91 */
add_file_name_to_url(CURL * curl,char ** inurlp,const char * filename)92 CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
93 {
94 CURLcode result = CURLE_URL_MALFORMAT;
95 CURLUcode uerr;
96 CURLU *uh = curl_url();
97 char *path = NULL;
98 char *query = NULL;
99 if(uh) {
100 char *ptr;
101 uerr = curl_url_set(uh, CURLUPART_URL, *inurlp,
102 CURLU_GUESS_SCHEME|CURLU_NON_SUPPORT_SCHEME);
103 if(uerr) {
104 result = urlerr_cvt(uerr);
105 goto fail;
106 }
107 uerr = curl_url_get(uh, CURLUPART_PATH, &path, 0);
108 if(uerr) {
109 result = urlerr_cvt(uerr);
110 goto fail;
111 }
112 uerr = curl_url_get(uh, CURLUPART_QUERY, &query, 0);
113 if(!uerr && query) {
114 curl_free(query);
115 curl_free(path);
116 curl_url_cleanup(uh);
117 return CURLE_OK;
118 }
119 ptr = strrchr(path, '/');
120 if(!ptr || !*++ptr) {
121 /* The URL path has no file name part, add the local file name. In order
122 to be able to do so, we have to create a new URL in another buffer.*/
123
124 /* We only want the part of the local path that is on the right
125 side of the rightmost slash and backslash. */
126 const char *filep = strrchr(filename, '/');
127 char *file2 = strrchr(filep?filep:filename, '\\');
128 char *encfile;
129
130 if(file2)
131 filep = file2 + 1;
132 else if(filep)
133 filep++;
134 else
135 filep = filename;
136
137 /* URL encode the file name */
138 encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
139 if(encfile) {
140 char *newpath;
141 char *newurl;
142 if(ptr)
143 /* there is a trailing slash on the path */
144 newpath = aprintf("%s%s", path, encfile);
145 else
146 /* there is no trailing slash on the path */
147 newpath = aprintf("%s/%s", path, encfile);
148
149 curl_free(encfile);
150
151 if(!newpath)
152 goto fail;
153 uerr = curl_url_set(uh, CURLUPART_PATH, newpath, 0);
154 free(newpath);
155 if(uerr) {
156 result = urlerr_cvt(uerr);
157 goto fail;
158 }
159 uerr = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_DEFAULT_SCHEME);
160 if(uerr) {
161 result = urlerr_cvt(uerr);
162 goto fail;
163 }
164 free(*inurlp);
165 *inurlp = newurl;
166 result = CURLE_OK;
167 }
168 }
169 else
170 /* nothing to do */
171 result = CURLE_OK;
172 }
173 fail:
174 curl_url_cleanup(uh);
175 curl_free(path);
176 return result;
177 }
178
179 /* Extracts the name portion of the URL.
180 * Returns a pointer to a heap-allocated string or NULL if
181 * no name part, at location indicated by first argument.
182 */
get_url_file_name(char ** filename,const char * url)183 CURLcode get_url_file_name(char **filename, const char *url)
184 {
185 const char *pc, *pc2;
186 CURLU *uh = curl_url();
187 char *path = NULL;
188 CURLUcode uerr;
189
190 if(!uh)
191 return CURLE_OUT_OF_MEMORY;
192
193 *filename = NULL;
194
195 uerr = curl_url_set(uh, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
196 if(!uerr) {
197 uerr = curl_url_get(uh, CURLUPART_PATH, &path, 0);
198 if(!uerr) {
199 curl_url_cleanup(uh);
200
201 pc = strrchr(path, '/');
202 pc2 = strrchr(pc ? pc + 1 : path, '\\');
203 if(pc2)
204 pc = pc2;
205
206 if(pc)
207 /* duplicate the string beyond the slash */
208 pc++;
209 else
210 /* no slash => empty string */
211 pc = "";
212
213 *filename = strdup(pc);
214 curl_free(path);
215 if(!*filename)
216 return CURLE_OUT_OF_MEMORY;
217
218 #if defined(_WIN32) || defined(MSDOS)
219 {
220 char *sanitized;
221 SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0);
222 Curl_safefree(*filename);
223 if(sc) {
224 if(sc == SANITIZE_ERR_OUT_OF_MEMORY)
225 return CURLE_OUT_OF_MEMORY;
226 return CURLE_URL_MALFORMAT;
227 }
228 *filename = sanitized;
229 }
230 #endif /* _WIN32 || MSDOS */
231
232 /* in case we built debug enabled, we allow an environment variable
233 * named CURL_TESTDIR to prefix the given file name to put it into a
234 * specific directory
235 */
236 #ifdef DEBUGBUILD
237 {
238 char *tdir = curlx_getenv("CURL_TESTDIR");
239 if(tdir) {
240 char *alt = aprintf("%s/%s", tdir, *filename);
241 Curl_safefree(*filename);
242 *filename = alt;
243 curl_free(tdir);
244 if(!*filename)
245 return CURLE_OUT_OF_MEMORY;
246 }
247 }
248 #endif
249 return CURLE_OK;
250 }
251 }
252 curl_url_cleanup(uh);
253 return urlerr_cvt(uerr);
254 }
255