Last modified: Nov 15, 2024 By Alexander Williams

Flask send_from_directory: Serve Files Securely from Directories

Flask's send_from_directory() function provides a secure way to serve files from specific directories in your web application. It's particularly useful when you need to serve files dynamically.

Basic Usage

Here's how to implement basic file serving using send_from_directory. This approach is more secure than directly exposing your file system through static folders.


from flask import Flask, send_from_directory

app = Flask(__name__)

# Route to serve files from a specific directory
@app.route('/downloads/')
def download_file(filename):
    # Serve files from the 'uploads' directory
    return send_from_directory('uploads', filename)

if __name__ == '__main__':
    app.run(debug=True)

Security Features

Path Traversal Protection: send_from_directory automatically protects against directory traversal attacks by sanitizing the filename parameter.

Like send_file(), it handles proper MIME type detection and secure file serving.

Advanced Configuration


@app.route('/files/')
def serve_file(filename):
    return send_from_directory(
        'uploads',
        filename,
        as_attachment=True,  # Force download
        mimetype='application/pdf',  # Specify MIME type
        conditional=True  # Enable conditional responses
    )

Error Handling

It's important to handle file not found scenarios gracefully. Here's how to implement proper error handling:


from flask import abort
import os

@app.route('/secure-files/')
def secure_file(filename):
    try:
        return send_from_directory('secure_uploads', filename)
    except FileNotFoundError:
        abort(404)  # Return 404 if file doesn't exist

Configuration Options

Key parameters for send_from_directory include:

  • directory: The directory where files are stored
  • path: The file path within the directory
  • as_attachment: Force file download instead of display

Best Practices

Always validate file types and implement proper access controls before serving files:


ALLOWED_EXTENSIONS = {'pdf', 'txt', 'doc'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/safe-downloads/')
def safe_download(filename):
    if not allowed_file(filename):
        abort(400)  # Bad request for invalid file types
    return send_from_directory('downloads', filename)

Conclusion

The send_from_directory function provides a secure and efficient way to serve files in Flask applications. Remember to always implement proper security measures and error handling.