xref: /curl/src/tool_operhlp.c (revision 9126b141)
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 = curl_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