I wrote a python script to automate the process of uploading images to an endpoint. The code is as follows:
import time
import requests
from pathlib import Path
from random import randint
def single_campus_upload(image_file, property_id):
BASE_URL_CAMPUS = f'http://[redacted].up.railway.app/api/properties/{property_id}/images/'
# Open the image file in read-binary mode using the `with` statement to automatically close it after reading
with image_file.open(mode='rb') as f:
# Read the contents of the file into a bytes object
image_data = f.read()
# Send the POST request to the API endpoint with the image data
response = requests.post(BASE_URL_CAMPUS, data=image_data)
# Check the status code to see if the request was successful
if response.status_code >= 200 and response.status_code < 300:
# Parse the JSON response and print it in a readable format
print(response.json())
else:
# Print the status code and the raw response if the request was not successful
print(f'Request failed with status code {response.status_code}: {response.text}')
The code above throws an error, here is the traceback:
`
ConnectionResetError Traceback (most recent call last)
File ~/anaconda3/lib/python3.9/site-packages/urllib3/connectionpool.py:703, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)
702 # Make the request on the httplib connection object.
--> 703 httplib_response = self._make_request(
704 conn,
705 method,
706 url,
707 timeout=timeout_obj,
708 body=body,
709 headers=headers,
710 chunked=chunked,
711 )
713 # If we're going to release the connection in ``finally:``, then
714 # the response doesn't need to know about the connection. Otherwise
715 # it will also try to release it and we'll have a double-release
716 # mess.
File ~/anaconda3/lib/python3.9/site-packages/urllib3/connectionpool.py:398, in HTTPConnectionPool._make_request(self, conn, method, url, timeout, chunked, **httplib_request_kw)
397 else:
--> 398 conn.request(method, url, **httplib_request_kw)
400 # We are swallowing BrokenPipeError (errno.EPIPE) since the server is
401 # legitimately able to close the connection after sending a valid response.
402 # With this behaviour, the received response is still readable.
File ~/anaconda3/lib/python3.9/site-packages/urllib3/connection.py:239, in HTTPConnection.request(self, method, url, body, headers)
238 headers["User-Agent"] = _get_default_user_agent()
--> 239 super(HTTPConnection, self).request(method, url, body=body, headers=headers)
File ~/anaconda3/lib/python3.9/http/client.py:1285, in HTTPConnection.request(self, method, url, body, headers, encode_chunked)
1284 """Send a complete request to the server."""
-> 1285 self._send_request(method, url, body, headers, encode_chunked)
File ~/anaconda3/lib/python3.9/http/client.py:1331, in HTTPConnection._send_request(self, method, url, body, headers, encode_chunked)
1330 body = _encode(body, 'body')
-> 1331 self.endheaders(body, encode_chunked=encode_chunked)
File ~/anaconda3/lib/python3.9/http/client.py:1280, in HTTPConnection.endheaders(self, message_body, encode_chunked)
1279 raise CannotSendHeader()
-> 1280 self._send_output(message_body, encode_chunked=encode_chunked)
File ~/anaconda3/lib/python3.9/http/client.py:1079, in HTTPConnection._send_output(self, message_body, encode_chunked)
1077 chunk = f'{len(chunk):X}\r\n'.encode('ascii') + chunk \
1078 + b'\r\n'
-> 1079 self.send(chunk)
...
503 except MaxRetryError as e:
504 if isinstance(e.reason, ConnectTimeoutError):
505 # TODO: Remove this in 3.0.0: see #2811
ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
It uploads successfully if I manually upload the image to the end point, so I have no idea why the script throws the error. My guess is that the server (railway) stops the script because it is too rapid, but even after implementing a rate limiter, the problem persisted.
Other Relevant Information:
- The endpoint is a Django/DRF backend.
- The backend is hosted on railway's servers
- The images are uploaded to cloudinary for storage (This may be where the issue is coming from) `
Any help would be much appreciated. Thanks in advance.
*Update while writing this*
I tried running the API I'm posting to - locally in dev mode rather than prod, but I connected the image storage to cloudinary still, then I ran the script and I observed the same problem, so definitely, the problem is not from railway, but from cloudinary. Can't figure out what's wrong, maybe it's expecting the file data / content-type header in some format I'm not aware of?