xref: /aosp_15_r20/external/curl/src/tool_cb_hdr.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker 
26*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
27*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_UNISTD_H
28*6236dae4SAndroid Build Coastguard Worker #include <unistd.h>
29*6236dae4SAndroid Build Coastguard Worker #endif
30*6236dae4SAndroid Build Coastguard Worker 
31*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
32*6236dae4SAndroid Build Coastguard Worker 
33*6236dae4SAndroid Build Coastguard Worker #include "tool_cfgable.h"
34*6236dae4SAndroid Build Coastguard Worker #include "tool_doswin.h"
35*6236dae4SAndroid Build Coastguard Worker #include "tool_msgs.h"
36*6236dae4SAndroid Build Coastguard Worker #include "tool_cb_hdr.h"
37*6236dae4SAndroid Build Coastguard Worker #include "tool_cb_wrt.h"
38*6236dae4SAndroid Build Coastguard Worker #include "tool_operate.h"
39*6236dae4SAndroid Build Coastguard Worker #include "tool_libinfo.h"
40*6236dae4SAndroid Build Coastguard Worker 
41*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
42*6236dae4SAndroid Build Coastguard Worker 
43*6236dae4SAndroid Build Coastguard Worker static char *parse_filename(const char *ptr, size_t len);
44*6236dae4SAndroid Build Coastguard Worker 
45*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
46*6236dae4SAndroid Build Coastguard Worker #define BOLD "\x1b[1m"
47*6236dae4SAndroid Build Coastguard Worker #define BOLDOFF "\x1b[22m"
48*6236dae4SAndroid Build Coastguard Worker #else
49*6236dae4SAndroid Build Coastguard Worker #define BOLD "\x1b[1m"
50*6236dae4SAndroid Build Coastguard Worker /* Switch off bold by setting "all attributes off" since the explicit
51*6236dae4SAndroid Build Coastguard Worker    bold-off code (21) is not supported everywhere - like in the mac
52*6236dae4SAndroid Build Coastguard Worker    Terminal. */
53*6236dae4SAndroid Build Coastguard Worker #define BOLDOFF "\x1b[0m"
54*6236dae4SAndroid Build Coastguard Worker /* OSC 8 hyperlink escape sequence */
55*6236dae4SAndroid Build Coastguard Worker #define LINK "\x1b]8;;"
56*6236dae4SAndroid Build Coastguard Worker #define LINKST "\x1b\\"
57*6236dae4SAndroid Build Coastguard Worker #define LINKOFF LINK LINKST
58*6236dae4SAndroid Build Coastguard Worker #endif
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker #ifdef LINK
61*6236dae4SAndroid Build Coastguard Worker static void write_linked_location(CURL *curl, const char *location,
62*6236dae4SAndroid Build Coastguard Worker     size_t loclen, FILE *stream);
63*6236dae4SAndroid Build Coastguard Worker #endif
64*6236dae4SAndroid Build Coastguard Worker 
tool_write_headers(struct HdrCbData * hdrcbdata,FILE * stream)65*6236dae4SAndroid Build Coastguard Worker int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream)
66*6236dae4SAndroid Build Coastguard Worker {
67*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *h = hdrcbdata->headlist;
68*6236dae4SAndroid Build Coastguard Worker   int rc = 1;
69*6236dae4SAndroid Build Coastguard Worker   while(h) {
70*6236dae4SAndroid Build Coastguard Worker     /* not "handled", just show it */
71*6236dae4SAndroid Build Coastguard Worker     size_t len = strlen(h->data);
72*6236dae4SAndroid Build Coastguard Worker     if(len != fwrite(h->data, 1, len, stream))
73*6236dae4SAndroid Build Coastguard Worker       goto fail;
74*6236dae4SAndroid Build Coastguard Worker     h = h->next;
75*6236dae4SAndroid Build Coastguard Worker   }
76*6236dae4SAndroid Build Coastguard Worker   rc = 0; /* success */
77*6236dae4SAndroid Build Coastguard Worker fail:
78*6236dae4SAndroid Build Coastguard Worker   curl_slist_free_all(hdrcbdata->headlist);
79*6236dae4SAndroid Build Coastguard Worker   hdrcbdata->headlist = NULL;
80*6236dae4SAndroid Build Coastguard Worker   return rc;
81*6236dae4SAndroid Build Coastguard Worker }
82*6236dae4SAndroid Build Coastguard Worker 
83*6236dae4SAndroid Build Coastguard Worker 
84*6236dae4SAndroid Build Coastguard Worker /*
85*6236dae4SAndroid Build Coastguard Worker ** callback for CURLOPT_HEADERFUNCTION
86*6236dae4SAndroid Build Coastguard Worker */
87*6236dae4SAndroid Build Coastguard Worker 
tool_header_cb(char * ptr,size_t size,size_t nmemb,void * userdata)88*6236dae4SAndroid Build Coastguard Worker size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
89*6236dae4SAndroid Build Coastguard Worker {
90*6236dae4SAndroid Build Coastguard Worker   struct per_transfer *per = userdata;
91*6236dae4SAndroid Build Coastguard Worker   struct HdrCbData *hdrcbdata = &per->hdrcbdata;
92*6236dae4SAndroid Build Coastguard Worker   struct OutStruct *outs = &per->outs;
93*6236dae4SAndroid Build Coastguard Worker   struct OutStruct *heads = &per->heads;
94*6236dae4SAndroid Build Coastguard Worker   struct OutStruct *etag_save = &per->etag_save;
95*6236dae4SAndroid Build Coastguard Worker   const char *str = ptr;
96*6236dae4SAndroid Build Coastguard Worker   const size_t cb = size * nmemb;
97*6236dae4SAndroid Build Coastguard Worker   const char *end = (char *)ptr + cb;
98*6236dae4SAndroid Build Coastguard Worker   const char *scheme = NULL;
99*6236dae4SAndroid Build Coastguard Worker 
100*6236dae4SAndroid Build Coastguard Worker   if(!per->config)
101*6236dae4SAndroid Build Coastguard Worker     return CURL_WRITEFUNC_ERROR;
102*6236dae4SAndroid Build Coastguard Worker 
103*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
104*6236dae4SAndroid Build Coastguard Worker   if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
105*6236dae4SAndroid Build Coastguard Worker     warnf(per->config->global, "Header data exceeds single call write limit");
106*6236dae4SAndroid Build Coastguard Worker     return CURL_WRITEFUNC_ERROR;
107*6236dae4SAndroid Build Coastguard Worker   }
108*6236dae4SAndroid Build Coastguard Worker #endif
109*6236dae4SAndroid Build Coastguard Worker 
110*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
111*6236dae4SAndroid Build Coastguard Worker   /* Discard incomplete UTF-8 sequence buffered from body */
112*6236dae4SAndroid Build Coastguard Worker   if(outs->utf8seq[0])
113*6236dae4SAndroid Build Coastguard Worker     memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
114*6236dae4SAndroid Build Coastguard Worker #endif
115*6236dae4SAndroid Build Coastguard Worker 
116*6236dae4SAndroid Build Coastguard Worker   /*
117*6236dae4SAndroid Build Coastguard Worker    * Write header data when curl option --dump-header (-D) is given.
118*6236dae4SAndroid Build Coastguard Worker    */
119*6236dae4SAndroid Build Coastguard Worker 
120*6236dae4SAndroid Build Coastguard Worker   if(per->config->headerfile && heads->stream) {
121*6236dae4SAndroid Build Coastguard Worker     size_t rc = fwrite(ptr, size, nmemb, heads->stream);
122*6236dae4SAndroid Build Coastguard Worker     if(rc != cb)
123*6236dae4SAndroid Build Coastguard Worker       return rc;
124*6236dae4SAndroid Build Coastguard Worker     /* flush the stream to send off what we got earlier */
125*6236dae4SAndroid Build Coastguard Worker     if(fflush(heads->stream)) {
126*6236dae4SAndroid Build Coastguard Worker       errorf(per->config->global, "Failed writing headers to %s",
127*6236dae4SAndroid Build Coastguard Worker              per->config->headerfile);
128*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
129*6236dae4SAndroid Build Coastguard Worker     }
130*6236dae4SAndroid Build Coastguard Worker   }
131*6236dae4SAndroid Build Coastguard Worker 
132*6236dae4SAndroid Build Coastguard Worker   curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
133*6236dae4SAndroid Build Coastguard Worker   scheme = proto_token(scheme);
134*6236dae4SAndroid Build Coastguard Worker   if((scheme == proto_http || scheme == proto_https)) {
135*6236dae4SAndroid Build Coastguard Worker     long response = 0;
136*6236dae4SAndroid Build Coastguard Worker     curl_easy_getinfo(per->curl, CURLINFO_RESPONSE_CODE, &response);
137*6236dae4SAndroid Build Coastguard Worker 
138*6236dae4SAndroid Build Coastguard Worker     if((response/100 != 2) && (response/100 != 3))
139*6236dae4SAndroid Build Coastguard Worker       /* only care about etag and content-disposition headers in 2xx and 3xx
140*6236dae4SAndroid Build Coastguard Worker          responses */
141*6236dae4SAndroid Build Coastguard Worker       ;
142*6236dae4SAndroid Build Coastguard Worker     /*
143*6236dae4SAndroid Build Coastguard Worker      * Write etag to file when --etag-save option is given.
144*6236dae4SAndroid Build Coastguard Worker      */
145*6236dae4SAndroid Build Coastguard Worker     else if(per->config->etag_save_file && etag_save->stream &&
146*6236dae4SAndroid Build Coastguard Worker             /* match only header that start with etag (case insensitive) */
147*6236dae4SAndroid Build Coastguard Worker             checkprefix("etag:", str)) {
148*6236dae4SAndroid Build Coastguard Worker       const char *etag_h = &str[5];
149*6236dae4SAndroid Build Coastguard Worker       const char *eot = end - 1;
150*6236dae4SAndroid Build Coastguard Worker       if(*eot == '\n') {
151*6236dae4SAndroid Build Coastguard Worker         while(ISBLANK(*etag_h) && (etag_h < eot))
152*6236dae4SAndroid Build Coastguard Worker           etag_h++;
153*6236dae4SAndroid Build Coastguard Worker         while(ISSPACE(*eot))
154*6236dae4SAndroid Build Coastguard Worker           eot--;
155*6236dae4SAndroid Build Coastguard Worker 
156*6236dae4SAndroid Build Coastguard Worker         if(eot >= etag_h) {
157*6236dae4SAndroid Build Coastguard Worker           size_t etag_length = eot - etag_h + 1;
158*6236dae4SAndroid Build Coastguard Worker           /*
159*6236dae4SAndroid Build Coastguard Worker            * Truncate the etag save stream, it can have an existing etag value.
160*6236dae4SAndroid Build Coastguard Worker            */
161*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_FTRUNCATE
162*6236dae4SAndroid Build Coastguard Worker           if(ftruncate(fileno(etag_save->stream), 0)) {
163*6236dae4SAndroid Build Coastguard Worker             return CURL_WRITEFUNC_ERROR;
164*6236dae4SAndroid Build Coastguard Worker           }
165*6236dae4SAndroid Build Coastguard Worker #else
166*6236dae4SAndroid Build Coastguard Worker           if(fseek(etag_save->stream, 0, SEEK_SET)) {
167*6236dae4SAndroid Build Coastguard Worker             return CURL_WRITEFUNC_ERROR;
168*6236dae4SAndroid Build Coastguard Worker           }
169*6236dae4SAndroid Build Coastguard Worker #endif
170*6236dae4SAndroid Build Coastguard Worker 
171*6236dae4SAndroid Build Coastguard Worker           fwrite(etag_h, size, etag_length, etag_save->stream);
172*6236dae4SAndroid Build Coastguard Worker           /* terminate with newline */
173*6236dae4SAndroid Build Coastguard Worker           fputc('\n', etag_save->stream);
174*6236dae4SAndroid Build Coastguard Worker           (void)fflush(etag_save->stream);
175*6236dae4SAndroid Build Coastguard Worker         }
176*6236dae4SAndroid Build Coastguard Worker       }
177*6236dae4SAndroid Build Coastguard Worker     }
178*6236dae4SAndroid Build Coastguard Worker 
179*6236dae4SAndroid Build Coastguard Worker     /*
180*6236dae4SAndroid Build Coastguard Worker      * This callback sets the filename where output shall be written when
181*6236dae4SAndroid Build Coastguard Worker      * curl options --remote-name (-O) and --remote-header-name (-J) have
182*6236dae4SAndroid Build Coastguard Worker      * been simultaneously given and additionally server returns an HTTP
183*6236dae4SAndroid Build Coastguard Worker      * Content-Disposition header specifying a filename property.
184*6236dae4SAndroid Build Coastguard Worker      */
185*6236dae4SAndroid Build Coastguard Worker 
186*6236dae4SAndroid Build Coastguard Worker     else if(hdrcbdata->honor_cd_filename) {
187*6236dae4SAndroid Build Coastguard Worker       if((cb > 20) && checkprefix("Content-disposition:", str)) {
188*6236dae4SAndroid Build Coastguard Worker         const char *p = str + 20;
189*6236dae4SAndroid Build Coastguard Worker 
190*6236dae4SAndroid Build Coastguard Worker         /* look for the 'filename=' parameter
191*6236dae4SAndroid Build Coastguard Worker            (encoded filenames (*=) are not supported) */
192*6236dae4SAndroid Build Coastguard Worker         for(;;) {
193*6236dae4SAndroid Build Coastguard Worker           char *filename;
194*6236dae4SAndroid Build Coastguard Worker           size_t len;
195*6236dae4SAndroid Build Coastguard Worker 
196*6236dae4SAndroid Build Coastguard Worker           while((p < end) && *p && !ISALPHA(*p))
197*6236dae4SAndroid Build Coastguard Worker             p++;
198*6236dae4SAndroid Build Coastguard Worker           if(p > end - 9)
199*6236dae4SAndroid Build Coastguard Worker             break;
200*6236dae4SAndroid Build Coastguard Worker 
201*6236dae4SAndroid Build Coastguard Worker           if(memcmp(p, "filename=", 9)) {
202*6236dae4SAndroid Build Coastguard Worker             /* no match, find next parameter */
203*6236dae4SAndroid Build Coastguard Worker             while((p < end) && *p && (*p != ';'))
204*6236dae4SAndroid Build Coastguard Worker               p++;
205*6236dae4SAndroid Build Coastguard Worker             if((p < end) && *p)
206*6236dae4SAndroid Build Coastguard Worker               continue;
207*6236dae4SAndroid Build Coastguard Worker             else
208*6236dae4SAndroid Build Coastguard Worker               break;
209*6236dae4SAndroid Build Coastguard Worker           }
210*6236dae4SAndroid Build Coastguard Worker           p += 9;
211*6236dae4SAndroid Build Coastguard Worker 
212*6236dae4SAndroid Build Coastguard Worker           len = cb - (size_t)(p - str);
213*6236dae4SAndroid Build Coastguard Worker           filename = parse_filename(p, len);
214*6236dae4SAndroid Build Coastguard Worker           if(filename) {
215*6236dae4SAndroid Build Coastguard Worker             if(outs->stream) {
216*6236dae4SAndroid Build Coastguard Worker               /* indication of problem, get out! */
217*6236dae4SAndroid Build Coastguard Worker               free(filename);
218*6236dae4SAndroid Build Coastguard Worker               return CURL_WRITEFUNC_ERROR;
219*6236dae4SAndroid Build Coastguard Worker             }
220*6236dae4SAndroid Build Coastguard Worker 
221*6236dae4SAndroid Build Coastguard Worker             if(per->config->output_dir) {
222*6236dae4SAndroid Build Coastguard Worker               outs->filename = aprintf("%s/%s", per->config->output_dir,
223*6236dae4SAndroid Build Coastguard Worker                                        filename);
224*6236dae4SAndroid Build Coastguard Worker               free(filename);
225*6236dae4SAndroid Build Coastguard Worker               if(!outs->filename)
226*6236dae4SAndroid Build Coastguard Worker                 return CURL_WRITEFUNC_ERROR;
227*6236dae4SAndroid Build Coastguard Worker             }
228*6236dae4SAndroid Build Coastguard Worker             else
229*6236dae4SAndroid Build Coastguard Worker               outs->filename = filename;
230*6236dae4SAndroid Build Coastguard Worker 
231*6236dae4SAndroid Build Coastguard Worker             outs->is_cd_filename = TRUE;
232*6236dae4SAndroid Build Coastguard Worker             outs->s_isreg = TRUE;
233*6236dae4SAndroid Build Coastguard Worker             outs->fopened = FALSE;
234*6236dae4SAndroid Build Coastguard Worker             outs->alloc_filename = TRUE;
235*6236dae4SAndroid Build Coastguard Worker             hdrcbdata->honor_cd_filename = FALSE; /* done now! */
236*6236dae4SAndroid Build Coastguard Worker             if(!tool_create_output_file(outs, per->config))
237*6236dae4SAndroid Build Coastguard Worker               return CURL_WRITEFUNC_ERROR;
238*6236dae4SAndroid Build Coastguard Worker             if(tool_write_headers(&per->hdrcbdata, outs->stream))
239*6236dae4SAndroid Build Coastguard Worker               return CURL_WRITEFUNC_ERROR;
240*6236dae4SAndroid Build Coastguard Worker           }
241*6236dae4SAndroid Build Coastguard Worker           break;
242*6236dae4SAndroid Build Coastguard Worker         }
243*6236dae4SAndroid Build Coastguard Worker         if(!outs->stream && !tool_create_output_file(outs, per->config))
244*6236dae4SAndroid Build Coastguard Worker           return CURL_WRITEFUNC_ERROR;
245*6236dae4SAndroid Build Coastguard Worker         if(tool_write_headers(&per->hdrcbdata, outs->stream))
246*6236dae4SAndroid Build Coastguard Worker           return CURL_WRITEFUNC_ERROR;
247*6236dae4SAndroid Build Coastguard Worker       } /* content-disposition handling */
248*6236dae4SAndroid Build Coastguard Worker 
249*6236dae4SAndroid Build Coastguard Worker       if(hdrcbdata->honor_cd_filename &&
250*6236dae4SAndroid Build Coastguard Worker          hdrcbdata->config->show_headers) {
251*6236dae4SAndroid Build Coastguard Worker         /* still awaiting the Content-Disposition header, store the header in
252*6236dae4SAndroid Build Coastguard Worker            memory. Since it is not zero terminated, we need an extra dance. */
253*6236dae4SAndroid Build Coastguard Worker         char *clone = aprintf("%.*s", (int)cb, (char *)str);
254*6236dae4SAndroid Build Coastguard Worker         if(clone) {
255*6236dae4SAndroid Build Coastguard Worker           struct curl_slist *old = hdrcbdata->headlist;
256*6236dae4SAndroid Build Coastguard Worker           hdrcbdata->headlist = curl_slist_append(old, clone);
257*6236dae4SAndroid Build Coastguard Worker           free(clone);
258*6236dae4SAndroid Build Coastguard Worker           if(!hdrcbdata->headlist) {
259*6236dae4SAndroid Build Coastguard Worker             curl_slist_free_all(old);
260*6236dae4SAndroid Build Coastguard Worker             return CURL_WRITEFUNC_ERROR;
261*6236dae4SAndroid Build Coastguard Worker           }
262*6236dae4SAndroid Build Coastguard Worker         }
263*6236dae4SAndroid Build Coastguard Worker         else {
264*6236dae4SAndroid Build Coastguard Worker           curl_slist_free_all(hdrcbdata->headlist);
265*6236dae4SAndroid Build Coastguard Worker           hdrcbdata->headlist = NULL;
266*6236dae4SAndroid Build Coastguard Worker           return CURL_WRITEFUNC_ERROR;
267*6236dae4SAndroid Build Coastguard Worker         }
268*6236dae4SAndroid Build Coastguard Worker         return cb; /* done for now */
269*6236dae4SAndroid Build Coastguard Worker       }
270*6236dae4SAndroid Build Coastguard Worker     }
271*6236dae4SAndroid Build Coastguard Worker   }
272*6236dae4SAndroid Build Coastguard Worker   if(hdrcbdata->config->writeout) {
273*6236dae4SAndroid Build Coastguard Worker     char *value = memchr(ptr, ':', cb);
274*6236dae4SAndroid Build Coastguard Worker     if(value) {
275*6236dae4SAndroid Build Coastguard Worker       if(per->was_last_header_empty)
276*6236dae4SAndroid Build Coastguard Worker         per->num_headers = 0;
277*6236dae4SAndroid Build Coastguard Worker       per->was_last_header_empty = FALSE;
278*6236dae4SAndroid Build Coastguard Worker       per->num_headers++;
279*6236dae4SAndroid Build Coastguard Worker     }
280*6236dae4SAndroid Build Coastguard Worker     else if(ptr[0] == '\r' || ptr[0] == '\n')
281*6236dae4SAndroid Build Coastguard Worker       per->was_last_header_empty = TRUE;
282*6236dae4SAndroid Build Coastguard Worker   }
283*6236dae4SAndroid Build Coastguard Worker   if(hdrcbdata->config->show_headers &&
284*6236dae4SAndroid Build Coastguard Worker     (scheme == proto_http || scheme == proto_https ||
285*6236dae4SAndroid Build Coastguard Worker      scheme == proto_rtsp || scheme == proto_file)) {
286*6236dae4SAndroid Build Coastguard Worker     /* bold headers only for selected protocols */
287*6236dae4SAndroid Build Coastguard Worker     char *value = NULL;
288*6236dae4SAndroid Build Coastguard Worker 
289*6236dae4SAndroid Build Coastguard Worker     if(!outs->stream && !tool_create_output_file(outs, per->config))
290*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
291*6236dae4SAndroid Build Coastguard Worker 
292*6236dae4SAndroid Build Coastguard Worker     if(hdrcbdata->global->isatty &&
293*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
294*6236dae4SAndroid Build Coastguard Worker        tool_term_has_bold &&
295*6236dae4SAndroid Build Coastguard Worker #endif
296*6236dae4SAndroid Build Coastguard Worker        hdrcbdata->global->styled_output)
297*6236dae4SAndroid Build Coastguard Worker       value = memchr(ptr, ':', cb);
298*6236dae4SAndroid Build Coastguard Worker     if(value) {
299*6236dae4SAndroid Build Coastguard Worker       size_t namelen = value - ptr;
300*6236dae4SAndroid Build Coastguard Worker       fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", (int)namelen, ptr);
301*6236dae4SAndroid Build Coastguard Worker #ifndef LINK
302*6236dae4SAndroid Build Coastguard Worker       fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
303*6236dae4SAndroid Build Coastguard Worker #else
304*6236dae4SAndroid Build Coastguard Worker       if(curl_strnequal("Location", ptr, namelen)) {
305*6236dae4SAndroid Build Coastguard Worker         write_linked_location(per->curl, &value[1], cb - namelen - 1,
306*6236dae4SAndroid Build Coastguard Worker             outs->stream);
307*6236dae4SAndroid Build Coastguard Worker       }
308*6236dae4SAndroid Build Coastguard Worker       else
309*6236dae4SAndroid Build Coastguard Worker         fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
310*6236dae4SAndroid Build Coastguard Worker #endif
311*6236dae4SAndroid Build Coastguard Worker     }
312*6236dae4SAndroid Build Coastguard Worker     else
313*6236dae4SAndroid Build Coastguard Worker       /* not "handled", just show it */
314*6236dae4SAndroid Build Coastguard Worker       fwrite(ptr, cb, 1, outs->stream);
315*6236dae4SAndroid Build Coastguard Worker   }
316*6236dae4SAndroid Build Coastguard Worker   return cb;
317*6236dae4SAndroid Build Coastguard Worker }
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker /*
320*6236dae4SAndroid Build Coastguard Worker  * Copies a filename part and returns an ALLOCATED data buffer.
321*6236dae4SAndroid Build Coastguard Worker  */
parse_filename(const char * ptr,size_t len)322*6236dae4SAndroid Build Coastguard Worker static char *parse_filename(const char *ptr, size_t len)
323*6236dae4SAndroid Build Coastguard Worker {
324*6236dae4SAndroid Build Coastguard Worker   char *copy;
325*6236dae4SAndroid Build Coastguard Worker   char *p;
326*6236dae4SAndroid Build Coastguard Worker   char *q;
327*6236dae4SAndroid Build Coastguard Worker   char  stop = '\0';
328*6236dae4SAndroid Build Coastguard Worker 
329*6236dae4SAndroid Build Coastguard Worker   /* simple implementation of strndup() */
330*6236dae4SAndroid Build Coastguard Worker   copy = malloc(len + 1);
331*6236dae4SAndroid Build Coastguard Worker   if(!copy)
332*6236dae4SAndroid Build Coastguard Worker     return NULL;
333*6236dae4SAndroid Build Coastguard Worker   memcpy(copy, ptr, len);
334*6236dae4SAndroid Build Coastguard Worker   copy[len] = '\0';
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker   p = copy;
337*6236dae4SAndroid Build Coastguard Worker   if(*p == '\'' || *p == '"') {
338*6236dae4SAndroid Build Coastguard Worker     /* store the starting quote */
339*6236dae4SAndroid Build Coastguard Worker     stop = *p;
340*6236dae4SAndroid Build Coastguard Worker     p++;
341*6236dae4SAndroid Build Coastguard Worker   }
342*6236dae4SAndroid Build Coastguard Worker   else
343*6236dae4SAndroid Build Coastguard Worker     stop = ';';
344*6236dae4SAndroid Build Coastguard Worker 
345*6236dae4SAndroid Build Coastguard Worker   /* scan for the end letter and stop there */
346*6236dae4SAndroid Build Coastguard Worker   q = strchr(p, stop);
347*6236dae4SAndroid Build Coastguard Worker   if(q)
348*6236dae4SAndroid Build Coastguard Worker     *q = '\0';
349*6236dae4SAndroid Build Coastguard Worker 
350*6236dae4SAndroid Build Coastguard Worker   /* if the filename contains a path, only use filename portion */
351*6236dae4SAndroid Build Coastguard Worker   q = strrchr(p, '/');
352*6236dae4SAndroid Build Coastguard Worker   if(q) {
353*6236dae4SAndroid Build Coastguard Worker     p = q + 1;
354*6236dae4SAndroid Build Coastguard Worker     if(!*p) {
355*6236dae4SAndroid Build Coastguard Worker       Curl_safefree(copy);
356*6236dae4SAndroid Build Coastguard Worker       return NULL;
357*6236dae4SAndroid Build Coastguard Worker     }
358*6236dae4SAndroid Build Coastguard Worker   }
359*6236dae4SAndroid Build Coastguard Worker 
360*6236dae4SAndroid Build Coastguard Worker   /* If the filename contains a backslash, only use filename portion. The idea
361*6236dae4SAndroid Build Coastguard Worker      is that even systems that do not handle backslashes as path separators
362*6236dae4SAndroid Build Coastguard Worker      probably want the path removed for convenience. */
363*6236dae4SAndroid Build Coastguard Worker   q = strrchr(p, '\\');
364*6236dae4SAndroid Build Coastguard Worker   if(q) {
365*6236dae4SAndroid Build Coastguard Worker     p = q + 1;
366*6236dae4SAndroid Build Coastguard Worker     if(!*p) {
367*6236dae4SAndroid Build Coastguard Worker       Curl_safefree(copy);
368*6236dae4SAndroid Build Coastguard Worker       return NULL;
369*6236dae4SAndroid Build Coastguard Worker     }
370*6236dae4SAndroid Build Coastguard Worker   }
371*6236dae4SAndroid Build Coastguard Worker 
372*6236dae4SAndroid Build Coastguard Worker   /* make sure the filename does not end in \r or \n */
373*6236dae4SAndroid Build Coastguard Worker   q = strchr(p, '\r');
374*6236dae4SAndroid Build Coastguard Worker   if(q)
375*6236dae4SAndroid Build Coastguard Worker     *q = '\0';
376*6236dae4SAndroid Build Coastguard Worker 
377*6236dae4SAndroid Build Coastguard Worker   q = strchr(p, '\n');
378*6236dae4SAndroid Build Coastguard Worker   if(q)
379*6236dae4SAndroid Build Coastguard Worker     *q = '\0';
380*6236dae4SAndroid Build Coastguard Worker 
381*6236dae4SAndroid Build Coastguard Worker   if(copy != p)
382*6236dae4SAndroid Build Coastguard Worker     memmove(copy, p, strlen(p) + 1);
383*6236dae4SAndroid Build Coastguard Worker 
384*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(MSDOS)
385*6236dae4SAndroid Build Coastguard Worker   {
386*6236dae4SAndroid Build Coastguard Worker     char *sanitized;
387*6236dae4SAndroid Build Coastguard Worker     SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0);
388*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(copy);
389*6236dae4SAndroid Build Coastguard Worker     if(sc)
390*6236dae4SAndroid Build Coastguard Worker       return NULL;
391*6236dae4SAndroid Build Coastguard Worker     copy = sanitized;
392*6236dae4SAndroid Build Coastguard Worker   }
393*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 || MSDOS */
394*6236dae4SAndroid Build Coastguard Worker 
395*6236dae4SAndroid Build Coastguard Worker   /* in case we built debug enabled, we allow an environment variable
396*6236dae4SAndroid Build Coastguard Worker    * named CURL_TESTDIR to prefix the given filename to put it into a
397*6236dae4SAndroid Build Coastguard Worker    * specific directory
398*6236dae4SAndroid Build Coastguard Worker    */
399*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
400*6236dae4SAndroid Build Coastguard Worker   {
401*6236dae4SAndroid Build Coastguard Worker     char *tdir = curl_getenv("CURL_TESTDIR");
402*6236dae4SAndroid Build Coastguard Worker     if(tdir) {
403*6236dae4SAndroid Build Coastguard Worker       char buffer[512]; /* suitably large */
404*6236dae4SAndroid Build Coastguard Worker       msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
405*6236dae4SAndroid Build Coastguard Worker       Curl_safefree(copy);
406*6236dae4SAndroid Build Coastguard Worker       copy = strdup(buffer); /* clone the buffer, we do not use the libcurl
407*6236dae4SAndroid Build Coastguard Worker                                 aprintf() or similar since we want to use the
408*6236dae4SAndroid Build Coastguard Worker                                 same memory code as the "real" parse_filename
409*6236dae4SAndroid Build Coastguard Worker                                 function */
410*6236dae4SAndroid Build Coastguard Worker       curl_free(tdir);
411*6236dae4SAndroid Build Coastguard Worker     }
412*6236dae4SAndroid Build Coastguard Worker   }
413*6236dae4SAndroid Build Coastguard Worker #endif
414*6236dae4SAndroid Build Coastguard Worker 
415*6236dae4SAndroid Build Coastguard Worker   return copy;
416*6236dae4SAndroid Build Coastguard Worker }
417*6236dae4SAndroid Build Coastguard Worker 
418*6236dae4SAndroid Build Coastguard Worker #ifdef LINK
419*6236dae4SAndroid Build Coastguard Worker /*
420*6236dae4SAndroid Build Coastguard Worker  * Treat the Location: header specially, by writing a special escape
421*6236dae4SAndroid Build Coastguard Worker  * sequence that adds a hyperlink to the displayed text. This makes
422*6236dae4SAndroid Build Coastguard Worker  * the absolute URL of the redirect clickable in supported terminals,
423*6236dae4SAndroid Build Coastguard Worker  * which could not happen otherwise for relative URLs. The Location:
424*6236dae4SAndroid Build Coastguard Worker  * header is supposed to always be absolute so this theoretically
425*6236dae4SAndroid Build Coastguard Worker  * should not be needed but the real world returns plenty of relative
426*6236dae4SAndroid Build Coastguard Worker  * URLs here.
427*6236dae4SAndroid Build Coastguard Worker  */
428*6236dae4SAndroid Build Coastguard Worker static
write_linked_location(CURL * curl,const char * location,size_t loclen,FILE * stream)429*6236dae4SAndroid Build Coastguard Worker void write_linked_location(CURL *curl, const char *location, size_t loclen,
430*6236dae4SAndroid Build Coastguard Worker                            FILE *stream) {
431*6236dae4SAndroid Build Coastguard Worker   /* This would so simple if CURLINFO_REDIRECT_URL were available here */
432*6236dae4SAndroid Build Coastguard Worker   CURLU *u = NULL;
433*6236dae4SAndroid Build Coastguard Worker   char *copyloc = NULL, *locurl = NULL, *scheme = NULL, *finalurl = NULL;
434*6236dae4SAndroid Build Coastguard Worker   const char *loc = location;
435*6236dae4SAndroid Build Coastguard Worker   size_t llen = loclen;
436*6236dae4SAndroid Build Coastguard Worker   int space_skipped = 0;
437*6236dae4SAndroid Build Coastguard Worker   char *vver = getenv("VTE_VERSION");
438*6236dae4SAndroid Build Coastguard Worker 
439*6236dae4SAndroid Build Coastguard Worker   if(vver) {
440*6236dae4SAndroid Build Coastguard Worker     long vvn = strtol(vver, NULL, 10);
441*6236dae4SAndroid Build Coastguard Worker     /* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since some
442*6236dae4SAndroid Build Coastguard Worker        of those versions have formatting bugs. (#10428) */
443*6236dae4SAndroid Build Coastguard Worker     if(0 < vvn && vvn <= 4801)
444*6236dae4SAndroid Build Coastguard Worker       goto locout;
445*6236dae4SAndroid Build Coastguard Worker   }
446*6236dae4SAndroid Build Coastguard Worker 
447*6236dae4SAndroid Build Coastguard Worker   /* Strip leading whitespace of the redirect URL */
448*6236dae4SAndroid Build Coastguard Worker   while(llen && (*loc == ' ' || *loc == '\t')) {
449*6236dae4SAndroid Build Coastguard Worker     ++loc;
450*6236dae4SAndroid Build Coastguard Worker     --llen;
451*6236dae4SAndroid Build Coastguard Worker     ++space_skipped;
452*6236dae4SAndroid Build Coastguard Worker   }
453*6236dae4SAndroid Build Coastguard Worker 
454*6236dae4SAndroid Build Coastguard Worker   /* Strip the trailing end-of-line characters, normally "\r\n" */
455*6236dae4SAndroid Build Coastguard Worker   while(llen && (loc[llen-1] == '\n' || loc[llen-1] == '\r'))
456*6236dae4SAndroid Build Coastguard Worker     --llen;
457*6236dae4SAndroid Build Coastguard Worker 
458*6236dae4SAndroid Build Coastguard Worker   /* CURLU makes it easy to handle the relative URL case */
459*6236dae4SAndroid Build Coastguard Worker   u = curl_url();
460*6236dae4SAndroid Build Coastguard Worker   if(!u)
461*6236dae4SAndroid Build Coastguard Worker     goto locout;
462*6236dae4SAndroid Build Coastguard Worker 
463*6236dae4SAndroid Build Coastguard Worker   /* Create a NUL-terminated and whitespace-stripped copy of Location: */
464*6236dae4SAndroid Build Coastguard Worker   copyloc = malloc(llen + 1);
465*6236dae4SAndroid Build Coastguard Worker   if(!copyloc)
466*6236dae4SAndroid Build Coastguard Worker     goto locout;
467*6236dae4SAndroid Build Coastguard Worker   memcpy(copyloc, loc, llen);
468*6236dae4SAndroid Build Coastguard Worker   copyloc[llen] = 0;
469*6236dae4SAndroid Build Coastguard Worker 
470*6236dae4SAndroid Build Coastguard Worker   /* The original URL to use as a base for a relative redirect URL */
471*6236dae4SAndroid Build Coastguard Worker   if(curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &locurl))
472*6236dae4SAndroid Build Coastguard Worker     goto locout;
473*6236dae4SAndroid Build Coastguard Worker   if(curl_url_set(u, CURLUPART_URL, locurl, 0))
474*6236dae4SAndroid Build Coastguard Worker     goto locout;
475*6236dae4SAndroid Build Coastguard Worker 
476*6236dae4SAndroid Build Coastguard Worker   /* Redirected location. This can be either absolute or relative. */
477*6236dae4SAndroid Build Coastguard Worker   if(curl_url_set(u, CURLUPART_URL, copyloc, 0))
478*6236dae4SAndroid Build Coastguard Worker     goto locout;
479*6236dae4SAndroid Build Coastguard Worker 
480*6236dae4SAndroid Build Coastguard Worker   if(curl_url_get(u, CURLUPART_URL, &finalurl, CURLU_NO_DEFAULT_PORT))
481*6236dae4SAndroid Build Coastguard Worker     goto locout;
482*6236dae4SAndroid Build Coastguard Worker 
483*6236dae4SAndroid Build Coastguard Worker   if(curl_url_get(u, CURLUPART_SCHEME, &scheme, 0))
484*6236dae4SAndroid Build Coastguard Worker     goto locout;
485*6236dae4SAndroid Build Coastguard Worker 
486*6236dae4SAndroid Build Coastguard Worker   if(!strcmp("http", scheme) ||
487*6236dae4SAndroid Build Coastguard Worker      !strcmp("https", scheme) ||
488*6236dae4SAndroid Build Coastguard Worker      !strcmp("ftp", scheme) ||
489*6236dae4SAndroid Build Coastguard Worker      !strcmp("ftps", scheme)) {
490*6236dae4SAndroid Build Coastguard Worker     fprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF,
491*6236dae4SAndroid Build Coastguard Worker             space_skipped, location,
492*6236dae4SAndroid Build Coastguard Worker             finalurl,
493*6236dae4SAndroid Build Coastguard Worker             (int)loclen - space_skipped, loc);
494*6236dae4SAndroid Build Coastguard Worker     goto locdone;
495*6236dae4SAndroid Build Coastguard Worker   }
496*6236dae4SAndroid Build Coastguard Worker 
497*6236dae4SAndroid Build Coastguard Worker   /* Not a "safe" URL: do not linkify it */
498*6236dae4SAndroid Build Coastguard Worker 
499*6236dae4SAndroid Build Coastguard Worker locout:
500*6236dae4SAndroid Build Coastguard Worker   /* Write the normal output in case of error or unsafe */
501*6236dae4SAndroid Build Coastguard Worker   fwrite(location, loclen, 1, stream);
502*6236dae4SAndroid Build Coastguard Worker 
503*6236dae4SAndroid Build Coastguard Worker locdone:
504*6236dae4SAndroid Build Coastguard Worker   if(u) {
505*6236dae4SAndroid Build Coastguard Worker     curl_free(finalurl);
506*6236dae4SAndroid Build Coastguard Worker     curl_free(scheme);
507*6236dae4SAndroid Build Coastguard Worker     curl_url_cleanup(u);
508*6236dae4SAndroid Build Coastguard Worker     free(copyloc);
509*6236dae4SAndroid Build Coastguard Worker   }
510*6236dae4SAndroid Build Coastguard Worker }
511*6236dae4SAndroid Build Coastguard Worker #endif
512