From 1032f56efae6bdab399d322fea2bd2da0d95365c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 31 Jul 2023 00:00:20 +0200 Subject: [PATCH] curl: make %output{} in -w specify a file to write to It can be used multiple times. Use %output{>>name} to append. Add docs. Test 990 and 991 verify. Idea: #11400 Suggested-by: ed0d2b2ce19451f2 Closes #11416 --- docs/cmdline-opts/write-out.d | 16 +++++++--- src/tool_writeout.c | 39 +++++++++++++++++++++++ tests/data/Makefile.inc | 2 +- tests/data/test990 | 57 +++++++++++++++++++++++++++++++++ tests/data/test991 | 60 +++++++++++++++++++++++++++++++++++ tests/runtests.pl | 6 ++++ 6 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 tests/data/test990 create mode 100644 tests/data/test991 diff --git a/docs/cmdline-opts/write-out.d b/docs/cmdline-opts/write-out.d index 9f7181f3a2..c3ac7d8075 100644 --- a/docs/cmdline-opts/write-out.d +++ b/docs/cmdline-opts/write-out.d @@ -25,10 +25,18 @@ output a newline by using \\n, a carriage return with \\r and a tab space with The output will be written to standard output, but this can be switched to standard error by using %{stderr}. -Output HTTP headers from the most recent request by using \fB%header{name}\fP -where \fBname\fP is the case insensitive name of the header (without the -trailing colon). The header contents are exactly as sent over the network, -with leading and trailing whitespace trimmed. Added in curl 7.84.0. +Output HTTP headers from the most recent request by using *%header{name}* +where *name* is the case insensitive name of the header (without the trailing +colon). The header contents are exactly as sent over the network, with leading +and trailing whitespace trimmed. Added in curl 7.84.0. + +Select a specific target destination file to write the output to, by using +*%output{name}* where *name* is the full file name. The output following that +instruction is then written to that file. More than one *%output{}* instruction +can be specified in the same write-out argument. If the file name cannot be +created, curl will leave the output to the one used prior to the *%output{}* +instruction. Use *%output{>>name}* to append data to an existing file. Added in +curl 8.3.0. .B NOTE: In Windows the %-symbol is a special symbol used to expand environment diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 2509d18b1a..0fc955d5b4 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -517,6 +517,7 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, bool done = FALSE; struct curl_certinfo *certinfo; CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo); + bool fclose_stream = FALSE; if(!writeinfo) return; @@ -556,9 +557,15 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, done = TRUE; break; case VAR_STDOUT: + if(fclose_stream) + fclose(stream); + fclose_stream = FALSE; stream = stdout; break; case VAR_STDERR: + if(fclose_stream) + fclose(stream); + fclose_stream = FALSE; stream = stderr; break; case VAR_JSON: @@ -600,6 +607,36 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, else fputs("%header{", stream); } + else if(!strncmp("output{", &ptr[1], 7)) { + bool append = FALSE; + ptr += 8; + if((ptr[0] == '>') && (ptr[1] == '>')) { + append = TRUE; + ptr += 2; + } + end = strchr(ptr, '}'); + if(end) { + char fname[512]; /* holds the longest file name */ + size_t flen = end - ptr; + if(flen < sizeof(fname)) { + FILE *stream2; + memcpy(fname, ptr, flen); + fname[flen] = 0; + stream2 = fopen(fname, append? FOPEN_APPENDTEXT : + FOPEN_WRITETEXT); + if(stream2) { + /* only change if the open worked */ + if(fclose_stream) + fclose(stream); + stream = stream2; + fclose_stream = TRUE; + } + } + ptr = end + 1; + } + else + fputs("%output{", stream); + } else { /* illegal syntax, then just output the characters that are used */ fputc('%', stream); @@ -632,4 +669,6 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, ptr++; } } + if(fclose_stream) + fclose(stream); } diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 6dab156c0e..3d2c51c4ac 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -124,7 +124,7 @@ test952 test953 test954 test955 test956 test957 test958 test959 test960 \ test961 test962 test963 test964 test965 test966 test967 test968 test969 \ test970 test971 test972 test973 test974 test975 test976 test977 test978 \ test979 test980 test981 test982 test983 test984 test985 test986 test987 \ -test988 test989 \ +test988 test989 test990 test991 \ \ test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \ diff --git a/tests/data/test990 b/tests/data/test990 new file mode 100644 index 0000000000..1b22d1aa92 --- /dev/null +++ b/tests/data/test990 @@ -0,0 +1,57 @@ + + + +HTTP +HTTP GET +-w + + + +# +# Server-side + + +HTTP/1.1 200 OK +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 +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +use -w %output{} + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w '%output{%LOGDIR/output}%{http_code}\n' + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +200 + + + diff --git a/tests/data/test991 b/tests/data/test991 new file mode 100644 index 0000000000..5a2cc62f30 --- /dev/null +++ b/tests/data/test991 @@ -0,0 +1,60 @@ + + + +HTTP +HTTP GET +-w + + + +# +# Server-side + + +HTTP/1.1 200 OK +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 +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +use -w %output{} append + + +line one + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w '%output{>>%LOGDIR/output}%{http_code}' + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +line one200 + + + diff --git a/tests/runtests.pl b/tests/runtests.pl index c24c3598be..050f40e787 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -1558,6 +1558,12 @@ sub singletest_check { @generated = @newgen; } + if($hash{'nonewline'}) { + # cut off the final newline from the final line of the + # output data + chomp($outfile[-1]); + } + $res = compare($runnerid, $testnum, $testname, "output ($filename)", \@generated, \@outfile); if($res) { -- 2.47.3