in libs/curl/src/tool_cb_hdr.c [63:273]
static void write_linked_location(CURL *curl, const char *location,
size_t loclen, FILE *stream);
#endif
/*
** callback for CURLOPT_HEADERFUNCTION
*/
size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
struct per_transfer *per = userdata;
struct HdrCbData *hdrcbdata = &per->hdrcbdata;
struct OutStruct *outs = &per->outs;
struct OutStruct *heads = &per->heads;
struct OutStruct *etag_save = &per->etag_save;
const char *str = ptr;
const size_t cb = size * nmemb;
const char *end = (char *)ptr + cb;
const char *scheme = NULL;
if(!per->config)
return CURL_WRITEFUNC_ERROR;
#ifdef DEBUGBUILD
if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
warnf(per->config->global, "Header data exceeds single call write limit");
return CURL_WRITEFUNC_ERROR;
}
#endif
#ifdef _WIN32
/* Discard incomplete UTF-8 sequence buffered from body */
if(outs->utf8seq[0])
memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
#endif
/*
* Write header data when curl option --dump-header (-D) is given.
*/
if(per->config->headerfile && heads->stream) {
size_t rc = fwrite(ptr, size, nmemb, heads->stream);
if(rc != cb)
return rc;
/* flush the stream to send off what we got earlier */
if(fflush(heads->stream)) {
errorf(per->config->global, "Failed writing headers to %s",
per->config->headerfile);
return CURL_WRITEFUNC_ERROR;
}
}
curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
scheme = proto_token(scheme);
if((scheme == proto_http || scheme == proto_https)) {
long response = 0;
curl_easy_getinfo(per->curl, CURLINFO_RESPONSE_CODE, &response);
if((response/100 != 2) && (response/100 != 3))
/* only care about etag and content-disposition headers in 2xx and 3xx
responses */
;
/*
* Write etag to file when --etag-save option is given.
*/
else if(per->config->etag_save_file && etag_save->stream &&
/* match only header that start with etag (case insensitive) */
checkprefix("etag:", str)) {
const char *etag_h = &str[5];
const char *eot = end - 1;
if(*eot == '\n') {
while(ISBLANK(*etag_h) && (etag_h < eot))
etag_h++;
while(ISSPACE(*eot))
eot--;
if(eot >= etag_h) {
size_t etag_length = eot - etag_h + 1;
/*
* Truncate the etag save stream, it can have an existing etag value.
*/
#ifdef HAVE_FTRUNCATE
if(ftruncate(fileno(etag_save->stream), 0)) {
return CURL_WRITEFUNC_ERROR;
}
#else
if(fseek(etag_save->stream, 0, SEEK_SET)) {
return CURL_WRITEFUNC_ERROR;
}
#endif
fwrite(etag_h, size, etag_length, etag_save->stream);
/* terminate with newline */
fputc('\n', etag_save->stream);
(void)fflush(etag_save->stream);
}
}
}
/*
* This callback sets the filename where output shall be written when
* curl options --remote-name (-O) and --remote-header-name (-J) have
* been simultaneously given and additionally server returns an HTTP
* Content-Disposition header specifying a filename property.
*/
else if(hdrcbdata->honor_cd_filename &&
(cb > 20) && checkprefix("Content-disposition:", str)) {
const char *p = str + 20;
/* look for the 'filename=' parameter
(encoded filenames (*=) are not supported) */
for(;;) {
char *filename;
size_t len;
while((p < end) && *p && !ISALPHA(*p))
p++;
if(p > end - 9)
break;
if(memcmp(p, "filename=", 9)) {
/* no match, find next parameter */
while((p < end) && *p && (*p != ';'))
p++;
if((p < end) && *p)
continue;
else
break;
}
p += 9;
len = cb - (size_t)(p - str);
filename = parse_filename(p, len);
if(filename) {
if(outs->stream) {
/* indication of problem, get out! */
free(filename);
return CURL_WRITEFUNC_ERROR;
}
if(per->config->output_dir) {
outs->filename = aprintf("%s/%s", per->config->output_dir,
filename);
free(filename);
if(!outs->filename)
return CURL_WRITEFUNC_ERROR;
}
else
outs->filename = filename;
outs->is_cd_filename = TRUE;
outs->s_isreg = TRUE;
outs->fopened = FALSE;
outs->alloc_filename = TRUE;
hdrcbdata->honor_cd_filename = FALSE; /* done now! */
if(!tool_create_output_file(outs, per->config))
return CURL_WRITEFUNC_ERROR;
}
break;
}
if(!outs->stream && !tool_create_output_file(outs, per->config))
return CURL_WRITEFUNC_ERROR;
}
}
if(hdrcbdata->config->writeout) {
char *value = memchr(ptr, ':', cb);
if(value) {
if(per->was_last_header_empty)
per->num_headers = 0;
per->was_last_header_empty = FALSE;
per->num_headers++;
}
else if(ptr[0] == '\r' || ptr[0] == '\n')
per->was_last_header_empty = TRUE;
}
if(hdrcbdata->config->show_headers &&
(scheme == proto_http || scheme == proto_https ||
scheme == proto_rtsp || scheme == proto_file)) {
/* bold headers only for selected protocols */
char *value = NULL;
if(!outs->stream && !tool_create_output_file(outs, per->config))
return CURL_WRITEFUNC_ERROR;
if(hdrcbdata->global->isatty &&
#ifdef _WIN32
tool_term_has_bold &&
#endif
hdrcbdata->global->styled_output)
value = memchr(ptr, ':', cb);
if(value) {
size_t namelen = value - ptr;
fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", (int)namelen, ptr);
#ifndef LINK
fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
#else
if(curl_strnequal("Location", ptr, namelen)) {
write_linked_location(per->curl, &value[1], cb - namelen - 1,
outs->stream);
}
else
fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
#endif
}
else
/* not "handled", just show it */
fwrite(ptr, cb, 1, outs->stream);
}
return cb;
}