UploadHandler Documentation
Overview
The UploadHandler class is an HTTP handler that enables authenticated users to upload files
to their website's file structure. It provides a secure API endpoint for handling multipart
form data uploads, typically used by the web-based file management interface for adding new
files to a user's account.
Purpose
This handler is part of the multi-tenant hosting service's file management system, allowing
users to upload various file types (images, documents, scripts, stylesheets, etc.) to their
allocated storage space. It handles the complex process of parsing multipart form data and
saving uploaded files to the appropriate user directory.
Core Functionality
This handler performs the following key operations:
1. Request Validation
- Only accepts POST requests (case-insensitive)
- Returns HTTP 405 (Method Not Allowed) for non-POST methods
- Expects multipart/form-data content type
2. Authentication & Authorization
- Extracts and validates the session ID from the request via getJavaSessionId()
- Verifies the session through SessionManager.getUsername()
- Rejects requests with invalid or expired sessions (HTTP 403)
- Ensures users can only upload files to their own directory space
3. Multipart Form Data Processing
The handler performs sophisticated multipart form parsing:
- Extracts the Content-Type header from the request to identify the boundary marker
- Converts the entire request body input stream to a byte array using inputStreamToBytes()
- Parses the multipart structure to extract headers using extractHeaders()
- Determines the uploaded file's content type using extractContentType()
- Delegates actual file saving to handleMultipartFormData() helper method
4. File Storage
- Passes the parsed body, content type, and username to handleMultipartFormData()
- Files are saved to user-specific directories based on the authenticated username
- Returns a success or failure message indicating the upload result
5. Response Handling
The handler returns different responses based on the outcome:
- Success (200): Returns the success message from handleMultipartFormData()
- Failure (500): Returns "Upload failed: {error message}" if an exception occurs
- Forbidden (403): Returns if session validation fails
- Method Not Allowed (405): Returns for non-POST requests
Request Format
Method: POST
Content-Type: multipart/form-data; boundary={boundary}
Body: Multipart form data containing the file(s) to upload
The request body follows the standard multipart/form-data format with parts separated by
boundary markers. Each part contains headers (Content-Disposition, Content-Type) followed
by the file content.
Response Format
Success Response:
- Status: 200 OK
- Content-Type: text/plain (implicit)
- Body: Success message from handleMultipartFormData()
Error Response:
- Status: 500 Internal Server Error
- Content-Type: text/plain (implicit)
- Body: "Upload failed: {exception message}"
Response Codes
- 200 OK: File was successfully uploaded and saved
- 403 Forbidden: Invalid or expired session
- 405 Method Not Allowed: Non-POST request method used
- 500 Internal Server Error: Exception occurred during upload processing
Security Features
- Session-based authentication: All requests require valid session credentials
- User isolation: Users can only upload files to their own directory structure
- Path validation: File destinations are determined server-side based on authenticated username
- Content-type extraction: Validates and processes the multipart boundary correctly
- Exception handling: Catches and reports errors without exposing sensitive system information
Error Handling
- Invalid session: Returns 403 Forbidden immediately
- Non-POST request: Returns 405 Method Not Allowed
- Parsing exceptions: Caught and returned as 500 with error message
- I/O exceptions: Caught and returned as 500 with error message
- Any other exceptions: Caught by general Exception handler, logged via printStackTrace()
Logging
The handler provides console logging for debugging:
- Logs "Reciving upload..." when processing begins
- Logs "bodyContentType: {content-type}" after extracting the uploaded file's content type
- Prints full stack traces for any exceptions that occur during processing
Use Cases
This handler is typically invoked when users:
- Upload images for their website (logos, photos, graphics)
- Upload stylesheets (CSS files) or scripts (JavaScript files)
- Upload HTML pages or PHP scripts
- Upload documents (PDFs, text files)
- Upload any other file type to their web hosting space
Dependencies
This handler relies on several helper methods and components:
- getJavaSessionId(): Extracts session identifier from the HTTP request
- SessionManager.getUsername(): Validates session and retrieves the authenticated username
- inputStreamToBytes(): Converts the InputStream to a byte array for processing
- extractHeaders(): Parses multipart headers from the request body
- extractContentType(): Extracts the Content-Type from multipart headers
- handleMultipartFormData(): Core method that processes the multipart data and saves the file
Behavior Notes
- Uses case-insensitive comparison for POST method check (equalsIgnoreCase)
- Loads the entire request body into memory as a byte array - may be problematic for very large files
- Extracts content type information twice (from request headers and from body headers)
- All exceptions are caught and returned as 500 errors with the exception message exposed to the client
- Response is converted to bytes twice (once for length calculation, once for writing)
- No explicit file size limits are enforced at this level
Performance Considerations
- Memory usage: The entire upload is buffered into memory before processing, which could cause issues with large files
- No streaming: Files are not streamed directly to disk, increasing memory pressure
- No chunking: Large uploads must complete in a single request
- Blocking I/O: The handler blocks while reading the entire request body
Potential Improvements
- Implement streaming uploads to reduce memory usage for large files
- Add file size limits to prevent memory exhaustion or abuse
- Validate file types and extensions for security
- Implement virus scanning for uploaded files
- Add rate limiting to prevent upload abuse
- Sanitize exception messages before sending to client
- Fix the double byte conversion in response handling
- Add progress reporting for large uploads
- Implement resumable upload support
- Add Content-Type header to responses explicitly
flowchart TD
A(["Start handle"]) --> B{"Request method
== POST?
(case-insensitive)"}
B -->|No| C["Send 405 Method Not Allowed"]
B -->|Yes| D["Get sessionId via
getJavaSessionId(exchange)"]
C --> Z(["End"])
D --> E["Get username from
SessionManager.getUsername(sessionId)"]
E --> F{"Username
is null?"}
F -->|Yes| G["Send 403 Forbidden
Close response body"]
F -->|No| H["TRY: Begin upload processing"]
G --> Z
H --> I["Log: 'Reciving upload...'"]
I --> J["Get request headers"]
J --> K["Extract Content-Type header
requestContentType = headers.getFirst('Content-Type')"]
K --> L["Convert request body to bytes:
body = inputStreamToBytes(exchange.getRequestBody())"]
L --> M["Extract headers from body:
bodyHeaders = extractHeaders(body, requestContentType)"]
M --> N["Extract content type from body:
bodyContentType = extractContentType(bodyHeaders)"]
N --> O["Log: 'bodyContentType: {bodyContentType}'"]
O --> P["Process multipart data:
response = handleMultipartFormData(body, requestContentType, user)"]
P --> Q["Convert response to bytes:
responseBytes = response.getBytes(UTF-8)"]
Q --> R["Send 200 response
with responseBytes.length"]
R --> S["Write response.getBytes()
to OutputStream"]
S --> T["Close OutputStream"]
T --> Z
H --> U["CATCH: Any Exception"]
U --> V["Print stack trace:
e.printStackTrace()"]
V --> W["Create error response:
'Upload failed: ' + e.getMessage()"]
W --> X["Send 500 Internal Server Error
with response.length()"]
X --> Y["Write response bytes
to OutputStream
Close stream"]
Y --> Z