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