Support ==@ syntax for query parameter values from file (#1218)

Co-authored-by: Vladimir Berkutov <vladimir.berkutov@gmail.com>

Co-authored-by: Vladimir Berkutov <vladimir.berkutov@gmail.com>
This commit is contained in:
Batuhan Taskaya 2021-12-01 21:09:39 +03:00 committed by GitHub
parent 00b366a81f
commit ba8e4097e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 5 deletions

View File

@ -598,12 +598,12 @@ GET /../../etc/password HTTP/1.1
There are a few different *request item* types that provide a convenient mechanism for specifying HTTP headers, simple JSON and form data, files, and URL parameters. There are a few different *request item* types that provide a convenient mechanism for specifying HTTP headers, simple JSON and form data, files, and URL parameters.
They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, and `:=@`. The ones with an `@` expect a file path as value. They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, `:=@` and `==@`. The ones with an `@` expect a file path as value.
| Item Type | Description | | Item Type | Description |
| -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | | HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` |
| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | | URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. For reading the value from a file, use `==@`. |
| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | | Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) |
| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | | Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) |
| File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | | File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request |

View File

@ -22,6 +22,7 @@ SEPARATOR_FILE_UPLOAD_TYPE = ';type=' # in already parsed file upload path only
SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@' SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@'
SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@' SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@'
SEPARATOR_QUERY_PARAM = '==' SEPARATOR_QUERY_PARAM = '=='
SEPARATOR_QUERY_EMBED_FILE = '==@'
# Separators that become request data # Separators that become request data
SEPARATOR_GROUP_DATA_ITEMS = frozenset({ SEPARATOR_GROUP_DATA_ITEMS = frozenset({
@ -40,6 +41,7 @@ SEPARATORS_GROUP_MULTIPART = frozenset({
# Separators for items whose value is a filename to be embedded # Separators for items whose value is a filename to be embedded
SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({ SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({
SEPARATOR_QUERY_EMBED_FILE,
SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_FILE_CONTENTS,
SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
}) })
@ -55,6 +57,7 @@ SEPARATOR_GROUP_ALL_ITEMS = frozenset({
SEPARATOR_HEADER, SEPARATOR_HEADER,
SEPARATOR_HEADER_EMPTY, SEPARATOR_HEADER_EMPTY,
SEPARATOR_QUERY_PARAM, SEPARATOR_QUERY_PARAM,
SEPARATOR_QUERY_EMBED_FILE,
SEPARATOR_DATA_STRING, SEPARATOR_DATA_STRING,
SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_RAW_JSON,
SEPARATOR_FILE_UPLOAD, SEPARATOR_FILE_UPLOAD,

View File

@ -8,7 +8,7 @@ from .constants import (
SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD,
SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY,
SEPARATOR_QUERY_PARAM, RequestType SEPARATOR_QUERY_PARAM, SEPARATOR_QUERY_EMBED_FILE, RequestType
) )
from .dicts import ( from .dicts import (
BaseMultiDict, MultipartRequestDataDict, RequestDataDict, BaseMultiDict, MultipartRequestDataDict, RequestDataDict,
@ -51,6 +51,10 @@ class RequestItems:
process_query_param_arg, process_query_param_arg,
instance.params, instance.params,
), ),
SEPARATOR_QUERY_EMBED_FILE: (
process_embed_query_param_arg,
instance.params,
),
SEPARATOR_FILE_UPLOAD: ( SEPARATOR_FILE_UPLOAD: (
process_file_upload_arg, process_file_upload_arg,
instance.files, instance.files,
@ -107,6 +111,10 @@ def process_query_param_arg(arg: KeyValueArg) -> str:
return arg.value return arg.value
def process_embed_query_param_arg(arg: KeyValueArg) -> str:
return load_text_file(arg).rstrip('\n')
def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]:
parts = arg.value.split(SEPARATOR_FILE_UPLOAD_TYPE) parts = arg.value.split(SEPARATOR_FILE_UPLOAD_TYPE)
filename = parts[0] filename = parts[0]

View File

@ -84,6 +84,7 @@ class TestItemParsing:
self.key_value_arg('file@' + FILE_PATH_ARG), self.key_value_arg('file@' + FILE_PATH_ARG),
self.key_value_arg('query==value'), self.key_value_arg('query==value'),
self.key_value_arg('string-embed=@' + FILE_PATH_ARG), self.key_value_arg('string-embed=@' + FILE_PATH_ARG),
self.key_value_arg('param-embed==@' + FILE_PATH_ARG),
self.key_value_arg('raw-json-embed:=@' + JSON_FILE_PATH_ARG), self.key_value_arg('raw-json-embed:=@' + JSON_FILE_PATH_ARG),
]) ])
@ -106,12 +107,13 @@ class TestItemParsing:
'bool': True, 'bool': True,
'list': ['a', 1, {}, False], 'list': ['a', 1, {}, False],
'obj': load_json_preserve_order_and_dupe_keys('{"a": "b"}'), 'obj': load_json_preserve_order_and_dupe_keys('{"a": "b"}'),
'string-embed': FILE_CONTENT, 'string-embed': FILE_CONTENT
} }
# Parsed query string parameters # Parsed query string parameters
assert items.params == { assert items.params == {
'query': 'value' 'query': 'value',
'param-embed': FILE_CONTENT.rstrip('\n')
} }
# Parsed file fields # Parsed file fields