mirror of
https://github.com/curl/curl.git
synced 2026-08-06 05:46:13 +03:00
tool: support --show-headers AND --remote-header-name
By keeping the headers in memory until we know the target file name, then output them all. Previously this option combination would cause an error. Add test 1310 and 1492 to verify. Adjusted test 1460 to work in the new conditions. Closes #15110
This commit is contained in:
parent
bc6072d245
commit
b0c82239c2
12 changed files with 240 additions and 69 deletions
|
|
@ -62,6 +62,25 @@ static void write_linked_location(CURL *curl, const char *location,
|
|||
size_t loclen, FILE *stream);
|
||||
#endif
|
||||
|
||||
int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream)
|
||||
{
|
||||
struct curl_slist *h = hdrcbdata->headlist;
|
||||
int rc = 1;
|
||||
while(h) {
|
||||
/* not "handled", just show it */
|
||||
size_t len = strlen(h->data);
|
||||
if(len != fwrite(h->data, 1, len, stream))
|
||||
goto fail;
|
||||
h = h->next;
|
||||
}
|
||||
rc = 0; /* success */
|
||||
fail:
|
||||
curl_slist_free_all(hdrcbdata->headlist);
|
||||
hdrcbdata->headlist = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_HEADERFUNCTION
|
||||
*/
|
||||
|
|
@ -164,63 +183,90 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
|
|||
* Content-Disposition header specifying a filename property.
|
||||
*/
|
||||
|
||||
else if(hdrcbdata->honor_cd_filename &&
|
||||
(cb > 20) && checkprefix("Content-disposition:", str)) {
|
||||
const char *p = str + 20;
|
||||
else if(hdrcbdata->honor_cd_filename) {
|
||||
if((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;
|
||||
/* 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 != ';'))
|
||||
while((p < end) && *p && !ISALPHA(*p))
|
||||
p++;
|
||||
if((p < end) && *p)
|
||||
continue;
|
||||
else
|
||||
if(p > end - 9)
|
||||
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(memcmp(p, "filename=", 9)) {
|
||||
/* no match, find next parameter */
|
||||
while((p < end) && *p && (*p != ';'))
|
||||
p++;
|
||||
if((p < end) && *p)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
p += 9;
|
||||
|
||||
if(per->config->output_dir) {
|
||||
outs->filename = aprintf("%s/%s", per->config->output_dir,
|
||||
filename);
|
||||
free(filename);
|
||||
if(!outs->filename)
|
||||
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;
|
||||
if(tool_write_headers(&per->hdrcbdata, outs->stream))
|
||||
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;
|
||||
}
|
||||
break;
|
||||
if(!outs->stream && !tool_create_output_file(outs, per->config))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
if(tool_write_headers(&per->hdrcbdata, outs->stream))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
} /* content-disposition handling */
|
||||
|
||||
if(hdrcbdata->honor_cd_filename &&
|
||||
hdrcbdata->config->show_headers) {
|
||||
/* still awaiting the Content-Disposition header, store the header in
|
||||
memory. Since it is not zero terminated, we need an extra dance. */
|
||||
char *clone = aprintf("%.*s", (int)cb, (char *)str);
|
||||
if(clone) {
|
||||
struct curl_slist *old = hdrcbdata->headlist;
|
||||
hdrcbdata->headlist = curl_slist_append(old, clone);
|
||||
free(clone);
|
||||
if(!hdrcbdata->headlist) {
|
||||
curl_slist_free_all(old);
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
curl_slist_free_all(hdrcbdata->headlist);
|
||||
hdrcbdata->headlist = NULL;
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
return cb; /* done for now */
|
||||
}
|
||||
if(!outs->stream && !tool_create_output_file(outs, per->config))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
if(hdrcbdata->config->writeout) {
|
||||
|
|
|
|||
|
|
@ -46,9 +46,12 @@ struct HdrCbData {
|
|||
struct OutStruct *outs;
|
||||
struct OutStruct *heads;
|
||||
struct OutStruct *etag_save;
|
||||
struct curl_slist *headlist;
|
||||
bool honor_cd_filename;
|
||||
};
|
||||
|
||||
int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream);
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_HEADERFUNCTION
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -345,7 +345,13 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
|
|||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if(per->hdrcbdata.headlist) {
|
||||
if(tool_write_headers(&per->hdrcbdata, outs->stream))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
rc = fwrite(buffer, sz, nmemb, outs->stream);
|
||||
}
|
||||
|
||||
if(bytes == rc)
|
||||
/* we added this amount of data to the output */
|
||||
|
|
|
|||
|
|
@ -2763,9 +2763,7 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
|
|||
}
|
||||
|
||||
if(!result && config->content_disposition) {
|
||||
if(config->show_headers)
|
||||
result = PARAM_CONTDISP_SHOW_HEADER;
|
||||
else if(config->resume_from_current)
|
||||
if(config->resume_from_current)
|
||||
result = PARAM_CONTDISP_RESUME_FROM;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -342,7 +342,6 @@ typedef enum {
|
|||
PARAM_NO_PREFIX,
|
||||
PARAM_NUMBER_TOO_LARGE,
|
||||
PARAM_NO_NOT_BOOLEAN,
|
||||
PARAM_CONTDISP_SHOW_HEADER, /* --include and --remote-header-name */
|
||||
PARAM_CONTDISP_RESUME_FROM, /* --continue-at and --remote-header-name */
|
||||
PARAM_READ_ERROR,
|
||||
PARAM_EXPAND_ERROR, /* --expand problem */
|
||||
|
|
|
|||
|
|
@ -67,8 +67,6 @@ const char *param2text(ParameterError error)
|
|||
return "too large number";
|
||||
case PARAM_NO_NOT_BOOLEAN:
|
||||
return "used '--no-' for option that is not a boolean";
|
||||
case PARAM_CONTDISP_SHOW_HEADER:
|
||||
return "showing headers and --remote-header-name cannot be combined";
|
||||
case PARAM_CONTDISP_RESUME_FROM:
|
||||
return "--continue-at and --remote-header-name cannot be combined";
|
||||
case PARAM_READ_ERROR:
|
||||
|
|
|
|||
|
|
@ -770,7 +770,8 @@ skip:
|
|||
free(per->uploadfile);
|
||||
if(global->parallel)
|
||||
free(per->errorbuffer);
|
||||
|
||||
curl_slist_free_all(per->hdrcbdata.headlist);
|
||||
per->hdrcbdata.headlist = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue