Skip to content

Upload File via HTTP (multipart/form-data)

Zero-dependency Python snippets for uploading files via HTTP using the standard library.

5 snippets available in this sub-category.


Simple

Simple file upload (multipart/form-data)

http upload file multipart post web

Simple file upload (multipart/form-data)

import urllib.request
import mimetypes
import uuid

def upload_file(url, file_path, field_name="file"):
    """Upload a file using multipart/form-data."""
    boundary = uuid.uuid4().hex
    content_type = f"multipart/form-data; boundary={boundary}"
    with open(file_path, "rb") as f:
        file_content = f.read()
    filename = file_path.split("/")[-1]
    body = (
        f"--{boundary}\r\n"
        f'Content-Disposition: form-data; name="{field_name}"; filename="{filename}"\r\n'
        f"Content-Type: {mimetypes.guess_type(filename)[0] or 'application/octet-stream'}\r\n\r\n"
    ).encode() + file_content + f"\r\n--{boundary}--\r\n".encode()
    req = urllib.request.Request(url, data=body, method="POST")
    req.add_header("Content-Type", content_type)
    req.add_header("Content-Length", str(len(body)))
    with urllib.request.urlopen(req) as response:
        return response.read().decode("utf-8")

# Example usage
# url = "https://httpbin.org/post"
# file_path = "example.txt"
# result = upload_file(url, file_path)
# print(result)

Notes

  • Manually constructs multipart/form-data body
  • Handles binary file uploads
  • For multiple files/fields, see below

Complex

Upload file with custom headers and error handling

http upload file headers error multipart post web

File upload with custom headers and error handling

import urllib.request
import mimetypes
import uuid
import urllib.error

def upload_file_safe(url, file_path, field_name="file", headers=None):
    """Upload a file with custom headers and error handling."""
    boundary = uuid.uuid4().hex
    content_type = f"multipart/form-data; boundary={boundary}"
    with open(file_path, "rb") as f:
        file_content = f.read()
    filename = file_path.split("/")[-1]
    body = (
        f"--{boundary}\r\n"
        f'Content-Disposition: form-data; name="{field_name}"; filename="{filename}"\r\n'
        f"Content-Type: {mimetypes.guess_type(filename)[0] or 'application/octet-stream'}\r\n\r\n"
    ).encode() + file_content + f"\r\n--{boundary}--\r\n".encode()
    req = urllib.request.Request(url, data=body, method="POST")
    req.add_header("Content-Type", content_type)
    req.add_header("Content-Length", str(len(body)))
    if headers:
        for k, v in headers.items():
            req.add_header(k, v)
    try:
        with urllib.request.urlopen(req) as response:
            return response.read().decode("utf-8")
    except urllib.error.HTTPError as e:
        print(f"HTTP error: {e.code} {e.reason}")
    except urllib.error.URLError as e:
        print(f"URL error: {e.reason}")
    except Exception as e:
        print(f"Unexpected error: {e}")
    return None

# Example usage
# url = "https://httpbin.org/post"
# file_path = "example.txt"
# headers = {"User-Agent": "stdlib-sniper/1.0"}
# result = upload_file_safe(url, file_path, headers=headers)
# print(result)

Notes

  • Handles HTTP and URL errors
  • Custom headers for authentication, user-agent, etc.

Upload multiple files (multipart/form-data)

http upload files multipart post web

Upload multiple files (multipart/form-data)

import urllib.request
import mimetypes
import uuid

def upload_multiple_files(url, files, field_name="file"):
    """Upload multiple files using multipart/form-data."""
    boundary = uuid.uuid4().hex
    content_type = f"multipart/form-data; boundary={boundary}"
    body = b""
    for file_path in files:
        with open(file_path, "rb") as f:
            file_content = f.read()
        filename = file_path.split("/")[-1]
        body += (
            f"--{boundary}\r\n"
            f'Content-Disposition: form-data; name="{field_name}"; filename="{filename}"\r\n'
            f"Content-Type: {mimetypes.guess_type(filename)[0] or 'application/octet-stream'}\r\n\r\n"
        ).encode() + file_content + b"\r\n"
    body += f"--{boundary}--\r\n".encode()
    req = urllib.request.Request(url, data=body, method="POST")
    req.add_header("Content-Type", content_type)
    req.add_header("Content-Length", str(len(body)))
    with urllib.request.urlopen(req) as response:
        return response.read().decode("utf-8")

# Example usage
# url = "https://httpbin.org/post"
# files = ["file1.txt", "file2.txt"]
# result = upload_multiple_files(url, files)
# print(result)

Notes

  • Each file is added as a separate part in the multipart body
  • Field name can be the same or different for each file

Upload file with progress reporting

http upload file progress multipart post web

File upload with progress reporting

import urllib.request
import mimetypes
import uuid
import os

def upload_file_with_progress(url, file_path, field_name="file", chunk_size=65536):
    """Upload a file with progress reporting (manual chunked upload)."""
    boundary = uuid.uuid4().hex
    content_type = f"multipart/form-data; boundary={boundary}"
    file_size = os.path.getsize(file_path)
    with open(file_path, "rb") as f:
        filename = file_path.split("/")[-1]
        preamble = (
            f"--{boundary}\r\n"
            f'Content-Disposition: form-data; name="{field_name}"; filename="{filename}"\r\n'
            f"Content-Type: {mimetypes.guess_type(filename)[0] or 'application/octet-stream'}\r\n\r\n"
        ).encode()
        postamble = f"\r\n--{boundary}--\r\n".encode()
        total = len(preamble) + file_size + len(postamble)
        req = urllib.request.Request(url, method="POST")
        req.add_header("Content-Type", content_type)
        req.add_header("Content-Length", str(total))
        # Manually build the body in chunks
        def body_iter():
            yield preamble
            sent = 0
            while True:
                chunk = f.read(chunk_size)
                if not chunk:
                    break
                sent += len(chunk)
                print(f"Uploaded {sent}/{file_size} bytes ({sent*100//file_size}%)", end="\r")
                yield chunk
            yield postamble
        # Combine all parts and send
        data = b"".join(body_iter())
        with urllib.request.urlopen(req, data=data) as response:
            print()
            return response.read().decode("utf-8")

# Example usage
# url = "https://httpbin.org/post"
# file_path = "largefile.bin"
# result = upload_file_with_progress(url, file_path)
# print(result)

Notes

  • Shows upload progress for large files
  • For true streaming, use lower-level sockets or third-party libraries

Edge Cases

Large/unsupported files and permission errors

http upload file error edge-case multipart post web

Edge cases: large/unsupported files and permission errors

def upload_file_safe(url, file_path, field_name="file", headers=None):
    # Function is defined in one of the above code block
    pass


# Edge case: Large file (may hit server or memory limits)
# Edge case: Unsupported file type (server may reject)
# Edge case: Permission error (file not readable)
try:
    upload_file_safe("https://httpbin.org/post", "/root/secret.txt")
except Exception as e:
    print(f"Error: {e}")

Notes

  • Large files may require chunked/streaming upload
  • Unsupported file types may be rejected by the server
  • Permission errors raise OSError/IOError

🔗 Cross-References

🏷️ Tags

http, upload, file, multipart, post, progress, headers, error, edge-case, web, binary

📝 Notes

  • Always validate file paths and types before uploading
  • For resumable uploads, use Range headers or third-party libraries
  • For async uploads, consider asyncio or external tools
  • For advanced multipart, see RFC 7578 or use requests library