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