2019-08-31 15:17:10 +02:00
|
|
|
import os
|
|
|
|
from io import BytesIO
|
|
|
|
from typing import Callable, Dict, IO, List, Optional, Tuple, Union
|
|
|
|
|
|
|
|
from httpie.cli.argtypes import KeyValueArg
|
|
|
|
from httpie.cli.constants import (
|
|
|
|
SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_RAW_JSON_FILE,
|
2019-12-02 10:42:33 +01:00
|
|
|
SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD,
|
|
|
|
SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, SEPARATOR_QUERY_PARAM,
|
2019-08-31 15:17:10 +02:00
|
|
|
)
|
|
|
|
from httpie.cli.dicts import (
|
|
|
|
RequestDataDict, RequestFilesDict, RequestHeadersDict, RequestJSONDataDict,
|
|
|
|
RequestQueryParamsDict,
|
|
|
|
)
|
|
|
|
from httpie.cli.exceptions import ParseError
|
|
|
|
from httpie.utils import (get_content_type, load_json_preserve_order)
|
|
|
|
|
|
|
|
|
|
|
|
class RequestItems:
|
|
|
|
|
|
|
|
def __init__(self, as_form=False, chunked=False):
|
|
|
|
self.headers = RequestHeadersDict()
|
|
|
|
self.data = RequestDataDict() if as_form else RequestJSONDataDict()
|
|
|
|
self.files = RequestFilesDict()
|
|
|
|
self.params = RequestQueryParamsDict()
|
|
|
|
self.chunked = chunked
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def from_args(
|
|
|
|
cls,
|
|
|
|
request_item_args: List[KeyValueArg],
|
|
|
|
as_form=False,
|
|
|
|
chunked=False
|
|
|
|
) -> 'RequestItems':
|
2019-12-02 10:42:33 +01:00
|
|
|
instance = cls(as_form=as_form, chunked=chunked)
|
2019-08-31 15:17:10 +02:00
|
|
|
rules: Dict[str, Tuple[Callable, dict]] = {
|
|
|
|
SEPARATOR_HEADER: (
|
|
|
|
process_header_arg,
|
|
|
|
instance.headers,
|
|
|
|
),
|
|
|
|
SEPARATOR_HEADER_EMPTY: (
|
|
|
|
process_empty_header_arg,
|
|
|
|
instance.headers,
|
|
|
|
),
|
|
|
|
SEPARATOR_QUERY_PARAM: (
|
|
|
|
process_query_param_arg,
|
|
|
|
instance.params,
|
|
|
|
),
|
|
|
|
SEPARATOR_FILE_UPLOAD: (
|
|
|
|
process_file_upload_arg,
|
|
|
|
instance.files,
|
|
|
|
),
|
|
|
|
SEPARATOR_DATA_STRING: (
|
|
|
|
process_data_item_arg,
|
|
|
|
instance.data,
|
|
|
|
),
|
|
|
|
SEPARATOR_DATA_EMBED_FILE_CONTENTS: (
|
|
|
|
process_data_embed_file_contents_arg,
|
|
|
|
instance.data,
|
|
|
|
),
|
|
|
|
SEPARATOR_DATA_RAW_JSON: (
|
|
|
|
process_data_raw_json_embed_arg,
|
|
|
|
instance.data,
|
|
|
|
),
|
|
|
|
SEPARATOR_DATA_EMBED_RAW_JSON_FILE: (
|
|
|
|
process_data_embed_raw_json_file_arg,
|
|
|
|
instance.data,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
for arg in request_item_args:
|
|
|
|
processor_func, target_dict = rules[arg.sep]
|
|
|
|
target_dict[arg.key] = processor_func(arg)
|
|
|
|
|
|
|
|
return instance
|
|
|
|
|
|
|
|
|
|
|
|
JSONType = Union[str, bool, int, list, dict]
|
|
|
|
|
|
|
|
|
|
|
|
def process_header_arg(arg: KeyValueArg) -> Optional[str]:
|
|
|
|
return arg.value or None
|
|
|
|
|
|
|
|
|
|
|
|
def process_empty_header_arg(arg: KeyValueArg) -> str:
|
|
|
|
if arg.value:
|
|
|
|
raise ParseError(
|
|
|
|
'Invalid item "%s" '
|
|
|
|
'(to specify an empty header use `Header;`)'
|
|
|
|
% arg.orig
|
|
|
|
)
|
|
|
|
return arg.value
|
|
|
|
|
|
|
|
|
|
|
|
def process_query_param_arg(arg: KeyValueArg) -> str:
|
|
|
|
return arg.value
|
|
|
|
|
|
|
|
|
|
|
|
def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]:
|
|
|
|
filename = arg.value
|
|
|
|
try:
|
|
|
|
with open(os.path.expanduser(filename), 'rb') as f:
|
|
|
|
contents = f.read()
|
|
|
|
except IOError as e:
|
|
|
|
raise ParseError('"%s": %s' % (arg.orig, e))
|
|
|
|
return (
|
|
|
|
os.path.basename(filename),
|
|
|
|
BytesIO(contents),
|
|
|
|
get_content_type(filename),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_file_item_chunked(arg: KeyValueArg):
|
|
|
|
fn = arg.value
|
|
|
|
try:
|
|
|
|
f = open(os.path.expanduser(fn), 'rb')
|
|
|
|
except IOError as e:
|
|
|
|
raise ParseError('"%s": %s' % (arg.orig, e))
|
|
|
|
return os.path.basename(fn), f, get_content_type(fn)
|
|
|
|
|
|
|
|
|
|
|
|
def process_data_item_arg(arg: KeyValueArg) -> str:
|
|
|
|
return arg.value
|
|
|
|
|
|
|
|
|
|
|
|
def process_data_embed_file_contents_arg(arg: KeyValueArg) -> str:
|
|
|
|
return load_text_file(arg)
|
|
|
|
|
|
|
|
|
|
|
|
def process_data_embed_raw_json_file_arg(arg: KeyValueArg) -> JSONType:
|
|
|
|
contents = load_text_file(arg)
|
|
|
|
value = load_json(arg, contents)
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
def process_data_raw_json_embed_arg(arg: KeyValueArg) -> JSONType:
|
|
|
|
value = load_json(arg, arg.value)
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
2019-09-17 09:07:12 +02:00
|
|
|
def load_text_file(item: KeyValueArg) -> str:
|
2019-08-31 15:17:10 +02:00
|
|
|
path = item.value
|
|
|
|
try:
|
|
|
|
with open(os.path.expanduser(path), 'rb') as f:
|
2019-08-31 18:21:10 +02:00
|
|
|
return f.read().decode()
|
2019-08-31 15:17:10 +02:00
|
|
|
except IOError as e:
|
|
|
|
raise ParseError('"%s": %s' % (item.orig, e))
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
raise ParseError(
|
|
|
|
'"%s": cannot embed the content of "%s",'
|
|
|
|
' not a UTF8 or ASCII-encoded text file'
|
|
|
|
% (item.orig, item.value)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def load_json(arg: KeyValueArg, contents: str) -> JSONType:
|
|
|
|
try:
|
|
|
|
return load_json_preserve_order(contents)
|
|
|
|
except ValueError as e:
|
|
|
|
raise ParseError('"%s": %s' % (arg.orig, e))
|