]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl/var: change byte offset syntax for assignments
authorDaniel Stenberg <daniel@haxx.se>
Mon, 30 Dec 2024 12:17:39 +0000 (13:17 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 30 Dec 2024 14:55:54 +0000 (15:55 +0100)
Follow-up to 40c264db617d0 after discussions on IRC.

The new style is

  name[0-99]=contents

and

  name[0-99]@filename

A) This does not cause the same problems with old curl versions trying
the new syntax as this way will cause old curls just fail with syntax
error and not risk using the wrong file.

B) Adds the same byte range support for "normal" assigns, which the
previous syntax did not. Thus lets a user get a partial content of a
variable etc.

Added test 790 and 791 to verify non-file assigns with ranges.

Closes #15862

docs/cmdline-opts/variable.md
src/var.c
tests/data/Makefile.am
tests/data/test784
tests/data/test785
tests/data/test786
tests/data/test787
tests/data/test788
tests/data/test789
tests/data/test790 [new file with mode: 0644]
tests/data/test791 [new file with mode: 0644]

index a84078ab8ebbc015cca4dfbd8c214e57905437b5..5b23e1fc4231b34a7d4fb5429ee229118cb51f4c 100644 (file)
@@ -36,14 +36,20 @@ the environment variable is not set, use --variable %name=content or
 --variable %name@content. Note that on some systems - but not all -
 environment variables are case insensitive.
 
-Added in curl 8.12.0: when getting contents from a file, you can request to
-get a byte range from it by appending ";[start-end]" to the filename, where
-*start* and *end* are byte offsets to include from the file. For example,
-asking for offset "2-10" means offset two to offset ten, including the byte
-offset 10, meaning 9 bytes in total. "2-2" means a single byte at offset 2.
-Not providing a second number implies to the end of the file. The start offset
-cannot be larger than the end offset. Asking for a range that is outside of
-the file size makes the variable contents empty.
+Added in curl 8.12.0: you can get a byte range from the source by appending
+`[start-end]` to the variable name, where *start* and *end* are byte offsets
+to include from the contents. For example, asking for offset "2-10" means
+offset two to offset ten, inclusive, resulting in 9 bytes in total. `2-2`
+means a single byte at offset 2. Not providing a second number implies to the
+end of data. The start offset cannot be larger than the end offset. Asking for
+a range that is outside of the file size makes the variable contents empty.
+For example, getting the first one hundred bytes from a given file:
+
+    curl --variable "fraction[0-99]@filename"
+
+Given a byte range that has no data results in an empty string. Asking for a
+range that is larger than the content makes curl use the piece of the data
+that exists.
 
 To assign a variable using contents from another variable, use
 --expand-variable. Like for example assigning a new variable using contents
index e42b5b2c40d8e59484e342fc647456e42a539160..f4b221e74a1ae13132b2a53f3be6e8bb7bbc87c5 100644 (file)
--- a/src/var.c
+++ b/src/var.c
@@ -389,6 +389,8 @@ ParameterError setvariable(struct GlobalConfig *global,
   bool import = FALSE;
   char *ge = NULL;
   char buf[MAX_VAR_LEN];
+  curl_off_t startoffset = 0;
+  curl_off_t endoffset = CURL_OFF_T_MAX;
 
   if(*input == '%') {
     import = TRUE;
@@ -423,42 +425,36 @@ ParameterError setvariable(struct GlobalConfig *global,
       clen = strlen(ge);
     }
   }
-  if(content)
-    ;
-  else if(*line == '@') {
-    /* read from file or stdin */
-    FILE *file;
-    bool use_stdin;
-    char *range;
-    struct dynbuf fname;
-    curl_off_t startoffset = 0;
-    curl_off_t endoffset = CURL_OFF_T_MAX;
-    line++;
-
-    Curl_dyn_init(&fname, MAX_FILENAME);
-
-    /* is there a byte range specified? ;[num-num] */
-    range = strstr(line, ";[");
-    if(range && ISDIGIT(range[2])) {
-      char *p = range;
+  if(*line == '[') {
+    /* is there a byte range specified? [num-num] */
+    if(ISDIGIT(line[1])) {
       char *endp;
-      if(curlx_strtoofft(&p[2], &endp, 10, &startoffset) || (*endp != '-'))
+      if(curlx_strtoofft(&line[1], &endp, 10, &startoffset) || (*endp != '-'))
         return PARAM_VAR_SYNTAX;
       else {
-        p = endp + 1; /* pass the '-' */
+        char *p = endp + 1; /* pass the '-' */
         if(*p != ']') {
           if(curlx_strtoofft(p, &endp, 10, &endoffset) || (*endp != ']'))
             return PARAM_VAR_SYNTAX;
+          line = &endp[1];  /* pass the ']' */
         }
+        else
+          line = &p[1]; /* pass the ']' */
       }
       if(startoffset > endoffset)
         return PARAM_VAR_SYNTAX;
-      /* create a dynbuf for the filename without the range */
-      if(Curl_dyn_addn(&fname, line, (range - line)))
-        return PARAM_NO_MEM;
-      /* point to the new file name buffer */
-      line = Curl_dyn_ptr(&fname);
     }
+  }
+  if(content)
+    ;
+  else if(*line == '@') {
+    /* read from file or stdin */
+    FILE *file;
+    bool use_stdin;
+    struct dynbuf fname;
+    line++;
+
+    Curl_dyn_init(&fname, MAX_FILENAME);
 
     use_stdin = !strcmp(line, "-");
     if(use_stdin)
@@ -485,9 +481,20 @@ ParameterError setvariable(struct GlobalConfig *global,
   }
   else if(*line == '=') {
     line++;
+    clen = strlen(line);
     /* this is the exact content */
     content = (char *)line;
-    clen = strlen(line);
+    if(startoffset || (endoffset != CURL_OFF_T_MAX)) {
+      if(startoffset >= (curl_off_t)clen)
+        clen = 0;
+      else {
+        /* make the end offset no larger than the last byte */
+        if(endoffset >= (curl_off_t)clen)
+          endoffset = clen - 1;
+        clen = (size_t)(endoffset - startoffset) + 1;
+        content += startoffset;
+      }
+    }
   }
   else {
     warnf(global, "Bad --variable syntax, skipping: %s", input);
index 73ef90920afa6261bf3bf3f4cb563f502a452552..b012848ca3fbfde44ecced3c13451ed665d96383 100644 (file)
@@ -110,7 +110,7 @@ test727 test728 test729 test730 test731 test732 test733 test734 test735 \
 test736 test737 test738 test739 test740 test741 test742 \
 \
 test780 test781 test782 test783 test784 test785 test786 test787 test788 \
-test789 \
+test789 test790 test791 \
 \
 test799 test800 test801 test802 test803 test804 test805 test806 test807 \
 test808 test809 test810 test811 test812 test813 test814 test815 test816 \
index 0c6acc67a83ee9fc46950b3b611f1d64bffe4c81..845a3acfc7f45b6193ae5263f035b3ed857efb3a 100644 (file)
@@ -35,7 +35,7 @@ http
 --variable with a file byte range
 </name>
 <command>
-http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable name"@%LOGDIR/in%TESTNUMBER;[5-15]" --expand-data '{{name}}'
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[5-15]@%LOGDIR/in%TESTNUMBER" --expand-data '{{name}}'
 </command>
 <file name="%LOGDIR/in%TESTNUMBER">
 On the first Monday of the month of April, 1625, the market town of Meung
index c46104a67a7035930f0cc3fc5fd79007fb33477c..6c8ae5dabb208ef530552541d569d21b2ac699cf 100644 (file)
@@ -35,7 +35,7 @@ http
 --variable with a file byte range without end
 </name>
 <command>
-http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable name"@%LOGDIR/in%TESTNUMBER;[5-]" --expand-data '{{name}}'
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[5-]@%LOGDIR/in%TESTNUMBER" --expand-data '{{name}}'
 </command>
 <file name="%LOGDIR/in%TESTNUMBER">
 On the first Monday of the month of April, 1625, the market town of Meung
index 5da450aae028e8389f8e60ee8bce8f4aa8194e00..bc5cca28d079e85568211de868a14a999fb57922 100644 (file)
@@ -35,7 +35,7 @@ http
 --variable with a file byte range, reading from stdin
 </name>
 <command>
-http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable name"@-;[5-15]" --expand-data '{{name}}'
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[5-15]@-" --expand-data '{{name}}'
 </command>
 <stdin>
 On the first Monday of the month of April, 1625, the market town of Meung
index 23dbad899381c6f5f541df8d7ce82fd6a78d9f2c..798d2d368f38b9efc0b6c85fcd04c10ba3ed11c9 100644 (file)
@@ -21,7 +21,7 @@ http
 --variable with a file byte range, bad range
 </name>
 <command>
-http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable name"@&LOGDIR/fooo;[15-14]" --expand-data '{{name}}'
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[15-14]@&LOGDIR/fooo" --expand-data '{{name}}'
 </command>
 </client>
 
index 268eeb6cc964089a4a8f10ebbc7e0cf5f2cbaad5..544732f7adb00d86ea02a14edff242e9a9214e57 100644 (file)
@@ -35,7 +35,7 @@ http
 --variable with a file and single-byte byte range
 </name>
 <command>
-http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable name"@%LOGDIR/in%TESTNUMBER;[15-15]" --expand-data '{{name}}'
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[15-15]@%LOGDIR/in%TESTNUMBER" --expand-data '{{name}}'
 </command>
 <file name="%LOGDIR/in%TESTNUMBER">
 On the first Monday of the month of April, 1625, the market town of Meung
index dd36303e24259cc01e731a3142ae2b2f431349ae..ce15967a0a00cd53f4a04099de909e281601f4ed 100644 (file)
@@ -35,7 +35,7 @@ http
 --variable with a file and byte range out of file
 </name>
 <command>
-http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable name"@%LOGDIR/in%TESTNUMBER;[75-85]" --expand-data '{{name}}'
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[75-85]@%LOGDIR/in%TESTNUMBER" --expand-data '{{name}}'
 </command>
 <file name="%LOGDIR/in%TESTNUMBER">
 On the first Monday of the month of April, 1625, the market town of Meung
diff --git a/tests/data/test790 b/tests/data/test790
new file mode 100644 (file)
index 0000000..1c7827b
--- /dev/null
@@ -0,0 +1,56 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+--variable
+</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>
+--variable with a byte range using plain assign
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[5-9]=0123456789abcdef" --expand-data '{{name}}'
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes" nonewline="yes">
+POST /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+Content-Length: 5
+Content-Type: application/x-www-form-urlencoded
+
+56789
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test791 b/tests/data/test791
new file mode 100644 (file)
index 0000000..6dcdc17
--- /dev/null
@@ -0,0 +1,56 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+--variable
+</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>
+--variable with a byte range using plain assign, out of range
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --variable "name[10-30]=0123456789abcdef" --expand-data '{{name}}'
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes" nonewline="yes">
+POST /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+Content-Length: 6
+Content-Type: application/x-www-form-urlencoded
+
+abcdef
+</protocol>
+</verify>
+</testcase>