]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl: make %output{} in -w specify a file to write to
authorDaniel Stenberg <daniel@haxx.se>
Sun, 30 Jul 2023 22:00:20 +0000 (00:00 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 31 Jul 2023 21:10:59 +0000 (23:10 +0200)
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
src/tool_writeout.c
tests/data/Makefile.inc
tests/data/test990 [new file with mode: 0644]
tests/data/test991 [new file with mode: 0644]
tests/runtests.pl

index 9f7181f3a269410d5f491f6c22e9e1a9592e0713..c3ac7d80754689776d2c520a6b903b0eb21dc850 100644 (file)
@@ -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
index 2509d18b1a6d51e3fab2b9a384774f0536851947..0fc955d5b4e07f9e48d0e93a633f7b6831b78c8a 100644 (file)
@@ -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);
 }
index 6dab156c0edc4102799742ac9234ac4b1894a516..3d2c51c4ac8f306dc2f27e2429b3ea21deff90a6 100644 (file)
@@ -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 (file)
index 0000000..1b22d1a
--- /dev/null
@@ -0,0 +1,57 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+-w
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data crlf="yes">
+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-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+use -w %output{}
+</name>
+ <command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w '%output{%LOGDIR/output}%{http_code}\n'
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+<file name="%LOGDIR/output" mode="text">
+200
+</file>
+</verify>
+</testcase>
diff --git a/tests/data/test991 b/tests/data/test991
new file mode 100644 (file)
index 0000000..5a2cc62
--- /dev/null
@@ -0,0 +1,60 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+-w
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data crlf="yes">
+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-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+use -w %output{} append
+</name>
+<file name="%LOGDIR/output" nonewline="yes">
+line one
+</file>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w '%output{>>%LOGDIR/output}%{http_code}'
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+<file name="%LOGDIR/output" nonewline="yes">
+line one200
+</file>
+</verify>
+</testcase>
index c24c3598bec6c84ed5b0c83a86e8c0720be9118c..050f40e787fd991ed3d1714b33d7ae4043f9648e 100755 (executable)
@@ -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) {