xref: /curl/src/tool_operhlp.c (revision cd2b4520)
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