xref: /third_party/curl/src/tool_operhlp.c (revision 13498266)
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
39void 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
58bool 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
68bool stdin_upload(const char *uploadfile)
69{
70  return (!strcmp(uploadfile, "-") ||
71          !strcmp(uploadfile, ".")) ? TRUE : FALSE;
72}
73
74/* Convert a CURLUcode into a CURLcode */
75CURLcode 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 */
92CURLcode 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  }
173fail:
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 */
183CURLcode 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