Skip to content

Introduction to File Uploads

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Introduction to File Uploads. We cover key concepts, practical examples, and best practices to help you master this topic.

File upload handling involves receiving files from clients over HTTP, validating them for security and correctness, processing them, and storing them reliably on the server.

What You'll Learn

By the end of this lesson, you will understand the file upload lifecycle, the HTTP mechanisms that enable uploads, and the core components every upload system needs.

Why It Matters

File uploads are a gateway for data into your system. A poorly implemented upload handler can expose your application to malicious files, server crashes, and data loss. According to OWASP, insecure file uploads are among the top web application risks.

Real-World Use

Durga Antivirus Pro accepts file uploads from users who want suspicious files analyzed. The upload system must validate file type, scan contents, reject malware, and store submissions securely before analysis begins.

Upload Lifecycle

flowchart LR
    Client[Browser/Client] -->|HTTP POST multipart| Server[Web Server]
    Server --> Validate[Validate File]
    Validate -->|Pass| Process[Process File]
    Validate -->|Fail| Error[Return Error]
    Process --> Store[Store File]
    Store --> Response[Return URL/ID]

HTTP File Upload Basics

When a browser uploads a file, it uses a multipart/form-data encoding in an HTTP POST request. Each file is sent as a separate part of the request body, with its own headers describing the filename and content type.

# upload_basics.py
# Demonstrating a minimal file upload handler
from http.server import HTTPServer, BaseHTTPRequestHandler
import cgi
import os

UPLOAD_DIR = "./uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)

class UploadHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_type = self.headers.get("Content-Type", "")
        if "multipart/form-data" not in content_type:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b"Expected multipart/form-data")
            return

        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={"REQUEST_METHOD": "POST"}
        )
        file_item = form.get("file")
        if not file_item or not file_item.filename:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b"No file provided")
            return

        filename = os.path.basename(file_item.filename)
        path = os.path.join(UPLOAD_DIR, filename)
        with open(path, "wb") as f:
            f.write(file_item.file.read())

        self.send_response(201)
        self.end_headers()
        response = f"Saved {filename} ({len(open(path, 'rb').read())} bytes)"
        self.wfile.write(response.encode())

handler = UploadHandler
port = 8080
print(f"Server on port {port}, POST files to /")
print(f"Example: curl -F 'file=@photo.jpg' http://localhost:{port}/")

Expected output:

Server on port 8080, POST files to /
Example: curl -F 'file=@photo.jpg' http://localhost:8080/

File Upload Anatomy

A multipart request body looks like this:

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="report.pdf"
Content-Type: application/pdf

(binary PDF content here)
------WebKitFormBoundary--

Each part includes a Content-Disposition header with the field name and original filename, plus a Content-Type header describing the file format.

Core Upload Components

Any file upload system needs these components:

  • Form parser: Extracts uploaded files from multipart request bodies
  • Validator: Checks file type, size, and content before processing
  • Storage handler: Writes files to disk, cloud storage, or a CDN
  • Security layer: Guards against path traversal, malware, and denial-of-service attacks

Common Mistakes

1. Trusting the Content-Type Header

The Content-Type header in a multipart part is set by the client and can be faked. Always validate the actual file content, not the declared type.

2. Storing Files in the Web Root

Files stored under the document root may be directly accessible via URL. Store uploads outside the web root and serve them through controlled endpoints.

3. Not Setting Upload Limits

Without size limits, an attacker can upload enormous files and exhaust disk space or memory.

4. Using Original Filenames

Filenames from users may contain path traversal sequences like ../../etc/passwd. Always sanitize or generate safe filenames.

5. Ignoring Concurrent Uploads

Multiple simultaneous uploads can overwhelm a server without Rate Limiting or connection pooling.

Practice Questions

1. What HTTP method and encoding type are used for file uploads?

POST with multipart/form-data encoding.

2. Why must the Content-Type header not be trusted?

The client sets it and can declare any value. The server must inspect the actual file bytes.

3. What information is in each multipart part?

Content-Disposition header with field name and filename, Content-Type header, and the file binary data.

4. What is the first validation an upload handler should perform?

Check that a file was actually provided and the request has the correct Content-Type.

Challenge

Trace the full lifecycle of a 10 MB image upload from browser click to server storage. List every step and what could go wrong at each stage.

FAQ

What encoding is used for file uploads?

Multipart/form-data splits the request body into parts, each with its own headers and binary content.

Can I use application/json for file uploads?

Not directly. JSON cannot encode binary data natively. You would need base64 encoding, which adds 33% overhead.

What is the maximum file size for uploads?

It depends on server configuration. Common limits range from 10 MB to 100 MB for most applications.

How does a server know an upload is finished?

The multipart boundary sequence signals the end. The server reads until it encounters the closing boundary.

Can a single request upload multiple files?

Yes. A multipart form can include multiple file fields, or an array of files under one field name.

Mini Project: Upload Counter

# upload_counter.py
import os
import time
from http.server import HTTPServer, BaseHTTPRequestHandler
import cgi

UPLOAD_DIR = "./uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
upload_count = 0
total_bytes = 0

class CountingUploadHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        global upload_count, total_bytes

        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={"REQUEST_METHOD": "POST"}
        )
        file_item = form.get("file")
        if not file_item or not file_item.filename:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b"No file")
            return

        data = file_item.file.read()
        safe_name = f"{int(time.time())}_{file_item.filename}"
        path = os.path.join(UPLOAD_DIR, safe_name)
        with open(path, "wb") as f:
            f.write(data)

        upload_count += 1
        total_bytes += len(data)

        self.send_response(201)
        self.end_headers()
        stats = f"Upload #{upload_count}, total {total_bytes} bytes"
        self.wfile.write(stats.encode())

    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        stats = f"Uploads: {upload_count}, Total bytes: {total_bytes}"
        self.wfile.write(stats.encode())

server = HTTPServer(("", 8080), CountingUploadHandler)
print("Server on :8080, POST to upload, GET for stats")
server.serve_forever()

Expected output:

Server on :8080, POST to upload, GET for stats

What's Next

You understand the basics of file uploads. Next, learn how multipart form data encoding works, then explore enforcing file size limits.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro