mirror of
https://github.com/curl/curl.git
synced 2026-06-13 00:45:37 +03:00
write-out: make %header{} able to output *all* occurances of a header
By appending `:all:[separator]` to the header name. The `[separator]` string is output between each header value if there are more than one to output. Test 764 and 765 verify Idea-by: kapsiR on github Ref: #18449 Closes #18491
This commit is contained in:
parent
522c991336
commit
6abe788bb8
5 changed files with 249 additions and 17 deletions
|
|
@ -93,6 +93,14 @@ The value of header `name` from the transfer's most recent server response.
|
|||
Unlike other variables, the variable name `header` is not in braces. For
|
||||
example `%header{date}`. Refer to --write-out remarks. (Added in 7.84.0)
|
||||
|
||||
Starting with 8.17.0, this output the contents of *all* header fields using a
|
||||
specific name - even for a whole redirect "chain" by appending
|
||||
`:all:[separator]` to the header name. The `[separator]` string (if not blank)
|
||||
is output between the headers if there are more than one. When more than one
|
||||
header is shown, they are output in the chronological order of appearance over
|
||||
the wire. To include a close brace (`}`) in the separator, escape it with a
|
||||
backslash: `\}`.
|
||||
|
||||
## `header_json`
|
||||
A JSON object with all HTTP response headers from the recent transfer. Values
|
||||
are provided as arrays, since in the case of multiple headers there can be
|
||||
|
|
|
|||
|
|
@ -615,6 +615,111 @@ static const char *outtime(const char *ptr, /* %time{ ... */
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static void separator(const char *sep, size_t seplen, FILE *stream)
|
||||
{
|
||||
while(seplen) {
|
||||
if(*sep == '\\') {
|
||||
switch(sep[1]) {
|
||||
case 'r':
|
||||
fputc('\r', stream);
|
||||
break;
|
||||
case 'n':
|
||||
fputc('\n', stream);
|
||||
break;
|
||||
case 't':
|
||||
fputc('\t', stream);
|
||||
break;
|
||||
case '}':
|
||||
fputc('}', stream);
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
/* unknown, just output this */
|
||||
fputc(sep[0], stream);
|
||||
fputc(sep[1], stream);
|
||||
break;
|
||||
}
|
||||
sep += 2;
|
||||
seplen -= 2;
|
||||
}
|
||||
else {
|
||||
fputc(*sep, stream);
|
||||
sep++;
|
||||
seplen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void output_header(struct per_transfer *per,
|
||||
FILE *stream,
|
||||
const char **pptr)
|
||||
{
|
||||
const char *ptr = *pptr;
|
||||
const char *end;
|
||||
end = strchr(ptr, '}');
|
||||
do {
|
||||
if(!end || (end && (end[-1] != '\\')))
|
||||
break;
|
||||
end = strchr(&end[1], '}');
|
||||
} while(end);
|
||||
if(end) {
|
||||
char hname[256]; /* holds the longest header field name */
|
||||
struct curl_header *header;
|
||||
const char *instr;
|
||||
const char *sep = NULL;
|
||||
size_t seplen = 0;
|
||||
size_t vlen = end - ptr;
|
||||
instr = memchr(ptr, ':', vlen);
|
||||
if(instr) {
|
||||
/* instructions follow */
|
||||
if(!strncmp(&instr[1], "all:", 4)) {
|
||||
sep = &instr[5];
|
||||
seplen = end - sep;
|
||||
vlen -= (seplen + 5);
|
||||
}
|
||||
}
|
||||
if(vlen < sizeof(hname)) {
|
||||
memcpy(hname, ptr, vlen);
|
||||
hname[vlen] = 0;
|
||||
if(sep) {
|
||||
/* get headers from all requests */
|
||||
int reqno = 0;
|
||||
size_t indno = 0;
|
||||
bool output = FALSE;
|
||||
do {
|
||||
if(CURLHE_OK == curl_easy_header(per->curl, hname, indno,
|
||||
CURLH_HEADER, reqno,
|
||||
&header)) {
|
||||
if(output)
|
||||
/* output separator */
|
||||
separator(sep, seplen, stream);
|
||||
fputs(header->value, stream);
|
||||
output = TRUE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
if((header->index + 1) < header->amount)
|
||||
indno++;
|
||||
else {
|
||||
++reqno;
|
||||
indno = 0;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
else {
|
||||
if(CURLHE_OK == curl_easy_header(per->curl, hname, 0,
|
||||
CURLH_HEADER, -1, &header))
|
||||
fputs(header->value, stream);
|
||||
}
|
||||
}
|
||||
ptr = end + 1;
|
||||
}
|
||||
else
|
||||
fputs("%header{", stream);
|
||||
*pptr = ptr;
|
||||
}
|
||||
|
||||
void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
||||
CURLcode per_result)
|
||||
{
|
||||
|
|
@ -699,22 +804,7 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
|||
}
|
||||
else if(!strncmp("header{", &ptr[1], 7)) {
|
||||
ptr += 8;
|
||||
end = strchr(ptr, '}');
|
||||
if(end) {
|
||||
char hname[256]; /* holds the longest header field name */
|
||||
struct curl_header *header;
|
||||
vlen = end - ptr;
|
||||
if(vlen < sizeof(hname)) {
|
||||
memcpy(hname, ptr, vlen);
|
||||
hname[vlen] = 0;
|
||||
if(CURLHE_OK == curl_easy_header(per->curl, hname, 0,
|
||||
CURLH_HEADER, -1, &header))
|
||||
fputs(header->value, stream);
|
||||
}
|
||||
ptr = end + 1;
|
||||
}
|
||||
else
|
||||
fputs("%header{", stream);
|
||||
output_header(per, stream, &ptr);
|
||||
}
|
||||
else if(!strncmp("time{", &ptr[1], 5)) {
|
||||
ptr = outtime(ptr, stream);
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ test727 test728 test729 test730 test731 test732 test733 test734 test735 \
|
|||
test736 test737 test738 test739 test740 test741 test742 test743 test744 \
|
||||
test745 test746 test747 test748 test749 test750 test751 test752 test753 \
|
||||
test754 test755 test756 test757 test758 test759 test760 test761 test762 \
|
||||
test763 \
|
||||
test763 test764 test765 \
|
||||
\
|
||||
test780 test781 test782 test783 test784 test785 test786 test787 test788 \
|
||||
test789 test790 test791 test792 test793 test794 test795 test796 test797 \
|
||||
|
|
|
|||
67
tests/data/test764
Normal file
67
tests/data/test764
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
-w
|
||||
%header
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data nocheck="yes">
|
||||
HTTP/1.1 301 Redirect
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
ETag: "21025-dc7-39462498"
|
||||
Accept-Ranges: bytes
|
||||
This: one
|
||||
This: two
|
||||
Content-Length: 6
|
||||
Location: %TESTNUMBER0002
|
||||
Content-Type: text/html
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data>
|
||||
<data2 nocheck="yes">
|
||||
HTTP/1.1 200 Not a redirect
|
||||
Accept-Ranges: bytes
|
||||
This: three
|
||||
This: four
|
||||
Content-Length: 6
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data2>
|
||||
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<features>
|
||||
headers-api
|
||||
</features>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
-w with multiple header output
|
||||
</name>
|
||||
<command option="no-output">
|
||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -w '%header{this:all:***}\n' -o %LOGDIR/%TESTNUMBER.out
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<stdout mode="text">
|
||||
one***two***three***four
|
||||
</stdout>
|
||||
</verify>
|
||||
</testcase>
|
||||
67
tests/data/test765
Normal file
67
tests/data/test765
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
-w
|
||||
%header
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data nocheck="yes">
|
||||
HTTP/1.1 301 Redirect
|
||||
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
ETag: "21025-dc7-39462498"
|
||||
Accept-Ranges: bytes
|
||||
This: one
|
||||
This: two
|
||||
Content-Length: 6
|
||||
Location: %TESTNUMBER0002
|
||||
Content-Type: text/html
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data>
|
||||
<data2 nocheck="yes">
|
||||
HTTP/1.1 200 Not a redirect
|
||||
Accept-Ranges: bytes
|
||||
This: three
|
||||
This: four
|
||||
Content-Length: 6
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data2>
|
||||
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<features>
|
||||
headers-api
|
||||
</features>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
-w with multiple header output using } in separator
|
||||
</name>
|
||||
<command option="no-output">
|
||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -w '%header{this:all:-{\}-}\n' -o %LOGDIR/%TESTNUMBER.out
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<stdout mode="text">
|
||||
one-{}-two-{}-three-{}-four
|
||||
</stdout>
|
||||
</verify>
|
||||
</testcase>
|
||||
Loading…
Add table
Add a link
Reference in a new issue