如何基于Python HTTP Server实现GET请求下载指定文件?
Got it, let's add the file download functionality to your existing HTTP server. Here's the modified code with clear explanations:
import cgi import os from urllib.parse import urlparse, parse_qs from http.server import BaseHTTPRequestHandler, HTTPServer class S(BaseHTTPRequestHandler): def _set_headers(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() def _html(self, message): content = f"<html><body><h1>{message}</h1></body></html>" return content.encode("utf8") def do_GET(self): # Parse the request URL to extract query parameters parsed_url = urlparse(self.path) query_params = parse_qs(parsed_url.query) # Check if a filename is provided in the GET request if 'filename' in query_params: filename = query_params['filename'][0] # Validate the file exists and is a regular file if not os.path.exists(filename): self.send_error(404, f"File '{filename}' not found on server") return if not os.path.isfile(filename): self.send_error(400, f"'{filename}' is not a valid file") return try: # Read the file content in binary mode with open(filename, 'rb') as file: file_content = file.read() # Set headers to trigger file download self.send_response(200) self.send_header('Content-Type', 'application/octet-stream') self.send_header('Content-Disposition', f'attachment; filename="{os.path.basename(filename)}"') self.send_header('Content-Length', str(len(file_content))) self.end_headers() # Send the file content to the client self.wfile.write(file_content) return except Exception as e: self.send_error(500, f"Error accessing file: {str(e)}") return # Default GET behavior: return the "hi!" message self._set_headers() self.wfile.write(self._html("hi!")) def do_HEAD(self): self._set_headers() def do_POST(self): form = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'], }) filename = form['file'].filename data = form['file'].file.read() open(filename, "wb").write(data) self._set_headers() self.wfile.write(self._html("hi!")) # Example to start the server (you can adjust port as needed) if __name__ == "__main__": server_address = ('', 8000) httpd = HTTPServer(server_address, S) print('Server running on port 8000...') httpd.serve_forever()
Key Changes Explained:
- Query Parameter Parsing: We use
urlparseandparse_qsto pull thefilenameparameter from the GET request URL (e.g.,http://localhost:8000/?filename=my_uploaded_file.txt). - File Validation: We check if the requested file exists and is a regular file (not a directory) to avoid serving unintended content or throwing errors.
- Download Headers:
Content-Type: application/octet-streamtells the browser this is a binary file meant for download.Content-Disposition: attachmentforces the browser to show a download prompt instead of trying to display the file directly.Content-Lengthprovides the file size to the browser for progress tracking.
- Error Handling: We send meaningful HTTP error codes (400 for invalid requests, 404 for missing files, 500 for server issues) to help clients understand what went wrong.
Important Security Note:
Right now, the server will serve any file it has access to on the system, which could let attackers access sensitive files via path traversal (e.g., filename=../secret.txt). To fix this, restrict file access to a specific directory:
# Define a safe directory for uploads/downloads ALLOWED_DIR = os.path.abspath("./safe_files") # In do_GET, add this check before accessing the file file_path = os.path.abspath(filename) if not file_path.startswith(ALLOWED_DIR): self.send_error(403, "Access denied: file is outside allowed directory") return
Make sure to update your POST handler to save files into this same ALLOWED_DIR too!
内容的提问来源于stack exchange,提问作者user12813016
相关产品推荐
相关产品推荐

