-
Notifications
You must be signed in to change notification settings - Fork 701
Open
Description
According to psf/requests#1997 when using files in requests, one is not supposed to provide headers, so that the library will take care of the multipart/form-data
with the appropriate content-type.
An example: (we wrote a custom extension just to do the XRAY API import)
# ...
files = {'file': (os.path.basename(result_file), open(result_file, 'rb'), 'application/xml')}
return self.post(api_url, files=files, params=params)
Will result in:
requests.exceptions.HTTPError: 415 Client Error: for url: https://[REDACTED]/rest/raven/1.0/api/import/execution/robot?projectKey=TCHCSIPDEV
This is due to the implementation in rest_client.py
:
def request(
self,
method="GET",
path="/",
data=None,
json=None,
flags=None,
params=None,
headers=None,
files=None,
trailing=None,
absolute=False,
advanced_mode=False,
):
"""
:param method:
:param path:
:param data:
:param json:
:param flags:
:param params:
:param headers:
:param files:
:param trailing: bool - OPTIONAL: Add trailing slash to url
:param absolute: bool, OPTIONAL: Do not prefix url, url is absolute
:param advanced_mode: bool, OPTIONAL: Return the raw response
:return:
"""
url = self.url_joiner(None if absolute else self.url, path, trailing)
params_already_in_url = True if "?" in url else False
if params or flags:
if params_already_in_url:
url += "&"
else:
url += "?"
if params:
url += urlencode(params or {})
if flags:
url += ("&" if params or params_already_in_url else "") + "&".join(flags or [])
json_dump = None
if files is None:
data = None if not data else dumps(data)
json_dump = None if not json else dumps(json)
self.log_curl_debug(
method=method,
url=url,
headers=headers,
data=data if data else json_dump,
)
headers = headers or self.default_headers # <------- Always provides headers
response = self._session.request(
method=method,
url=url,
headers=headers, # <------- Should be None when providing files, so that the requests library handles file upload with appropriate headers
data=data,
json=json,
timeout=self.timeout,
verify=self.verify_ssl,
files=files,
proxies=self.proxies,
cert=self.cert,
)
response.encoding = "utf-8"
log.debug("HTTP: %s %s -> %s %s", method, path, response.status_code, response.reason)
log.debug("HTTP: Response text -> %s", response.text)
if self.advanced_mode or advanced_mode:
return response
self.raise_for_status(response)
return response
If we change this to:
headers = headers or self.default_headers if files is None else None
Then the request will work, as the multipart/form-data
is appropriately handled by the requests library.
This is necessary in APIs like XRAY, where one can import result files, which are not JSON.
But it should also be applicable for JSON files.
Metadata
Metadata
Assignees
Labels
No labels