irondrop 2.7.0

Drop files, not dependencies - a well tested fully featured & battle-ready server in a single Rust binary with support for indexing through 10M files.
Documentation
# IronDrop Direct Upload Streaming (v2.7.0)

## Overview

IronDrop implements direct streaming uploads. Large request bodies are streamed to disk, avoiding unbounded memory growth. Small bodies are processed in memory.

**Status**: Production-ready (v2.7.0)
- Direct streaming implementation with bounded memory usage
- Handling from small to very large files
- Tests cover stability and cleanup
- Simple binary streaming path and straightforward API

## Key Features

### Direct streaming logic
- **Small uploads** (≤64MB): Processed in memory for optimal performance
- **Large uploads** (>64MB): Directly streamed to disk with constant memory usage
- **No size limits**: Removed artificial 10GB restrictions
- **Constant memory**: RAM usage stays at ~7MB regardless of file size

### Direct binary path
- **Raw binary uploads**: No multipart parsing complexity
- **Direct disk streaming**: Files written directly to storage
- **Automatic cleanup**: Temporary files managed transparently
- **Unified interface**: Upload handlers work seamlessly with both variants
- **Type safety**: Rust's type system ensures correct handling

### Security and resource management
- **Automatic cleanup**: Temporary files are automatically removed after request completion
- **Size limits**: Configurable limits prevent resource exhaustion
- **Path safety**: Secure temporary file creation with unique naming
- **Error handling**: Comprehensive error recovery with cleanup on failure

## Architecture

### RequestBody Enum

The core of the streaming system is the `RequestBody` enum that provides a unified interface for both memory and disk-based request bodies:

```rust
#[derive(Debug, Clone)]
pub enum RequestBody {
    /// Small request body stored in memory
    Memory(Vec<u8>),
    /// Large request body streamed to a temporary file
    File(PathBuf),
}
```

### Automatic Mode Selection

The HTTP layer automatically determines the appropriate storage method based on content size:

```rust
// Automatic streaming logic in http.rs
if content_length <= STREAMING_THRESHOLD {
    // Small upload: keep in memory
    let body_data = read_body_to_memory(stream, content_length)?;
    request.body = Some(RequestBody::Memory(body_data));
} else {
    // Large upload: stream to disk
    let temp_file_path = stream_body_to_disk(stream, content_length)?;
    request.body = Some(RequestBody::File(temp_file_path));
}
```

### Memory Threshold Configuration

```rust
/// Threshold for switching between memory and disk storage
/// Files larger than 64MB are automatically streamed to disk
/// This ensures total memory usage stays well below 128MB
const STREAM_TO_DISK_THRESHOLD: usize = 64 * 1024 * 1024; // 64MB
```

## Implementation Details

### HTTP Request Processing

The HTTP layer (`src/http.rs`) handles the automatic streaming logic:

1. **Content-Length Detection**: Extracts content length from HTTP headers
2. **Mode Selection**: Compares content length against streaming threshold
3. **Memory Processing**: Small uploads are read directly into memory
4. **Disk Streaming**: Large uploads are streamed to temporary files
5. **Request Construction**: Creates appropriate `RequestBody` variant

### Upload Handler Integration

Upload handlers (`src/upload.rs`) work transparently with both variants:

```rust
// Upload handlers automatically handle both memory and file variants
match &request.body {
    Some(RequestBody::Memory(data)) => {
        // Process in-memory data
        let cursor = Cursor::new(data.clone());
        let parser = MultipartParser::new(cursor, &boundary, config)?;
        // ... process multipart data
    }
    Some(RequestBody::File(path)) => {
        // Process file-based data
        let file = File::open(path)?;
        let parser = MultipartParser::new(file, &boundary, config)?;
        // ... process multipart data
    }
    None => return Err(AppError::invalid_multipart("No body")),
}
```

### Temporary File Management

The system uses secure temporary file creation and automatic cleanup:

```rust
// Secure temporary file creation
let temp_filename = format!(
    "{}{}_{}_{:x}.tmp",
    TEMP_FILE_PREFIX,
    std::process::id(),
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap_or_default()
        .as_nanos(),
    thread_rng().gen::<u32>()
);
```

### Automatic Cleanup

Temporary files are automatically cleaned up when the request is complete:

```rust
impl Drop for Request {
    fn drop(&mut self) {
        if let Some(RequestBody::File(path)) = &self.body {
            if path.exists() {
                let _ = std::fs::remove_file(path);
            }
        }
    }
}
```

## Performance Characteristics

### Memory Usage

| Upload Size | Storage Method | Memory Usage | Disk Usage |
|-------------|----------------|--------------|------------|
| 1KB - 64MB  | Memory         | ~Upload Size | None       |
| 64MB - 10GB+| Disk Streaming | ~64KB Buffer | Upload Size|

### Processing Speed

- **Small uploads**: Optimal performance with in-memory processing
- **Large uploads**: Consistent performance regardless of size
- **Concurrent uploads**: Each request handled independently
- **Resource protection**: No memory exhaustion from large uploads

### Scalability Benefits

1. **Memory Efficiency**: Large uploads don't consume system memory
2. **Concurrent Handling**: Multiple large uploads can be processed simultaneously
3. **Resource Predictability**: Memory usage remains bounded regardless of upload size
4. **System Stability**: Prevents out-of-memory conditions

## Testing

### HTTP Streaming Tests

The implementation includes comprehensive tests in `tests/http_streaming_test.rs`:

```rust
#[test]
fn test_small_body_memory_storage() {
    // Verifies small uploads are kept in memory
    let small_body = "a".repeat(500 * 1024); // 500KB
    // ... test implementation
}

#[test]
fn test_large_body_disk_streaming() {
    // Verifies large uploads are streamed to disk
    let large_body = "a".repeat(2 * 1024 * 1024); // 64MB
    // ... test implementation
}
```

### Test Coverage

- **Memory storage verification**: Confirms small uploads use memory storage
- **Disk streaming verification**: Confirms large uploads use disk storage
- **Automatic cleanup testing**: Verifies temporary files are removed
- **Error handling**: Tests cleanup on failure scenarios
- **Integration testing**: End-to-end upload functionality

## Configuration

### Environment Variables

```bash
# Optional: Override default streaming threshold
export IRONDROP_STREAMING_THRESHOLD=2097152  # 64MB
```

### CLI Configuration

The streaming system respects existing CLI configuration:

```bash
# Maximum upload size (affects both memory and disk uploads)
irondrop --max-upload-size 10GB

# Upload directory (where temporary files are created)
irondrop --directory /path/to/uploads
```

## Security Considerations

### Temporary File Security

1. **Unique naming**: Process ID and timestamp ensure unique filenames
2. **Secure location**: Temporary files created in upload directory
3. **Automatic cleanup**: Files removed immediately after processing
4. **Error cleanup**: Files removed even if processing fails

### Resource Protection

1. **Size limits**: Existing upload size limits apply to both variants
2. **Memory bounds**: Large uploads don't consume system memory
3. **Disk space**: Temporary files are cleaned up immediately
4. **Concurrent limits**: Thread pool limits prevent resource exhaustion

## Migration Guide

### Existing Code Compatibility

The streaming implementation is fully backward compatible. Existing upload handlers continue to work without modification:

```rust
// Before: Direct access to body data
let body_data = request.body.as_ref().unwrap();

// After: Pattern matching on RequestBody variants
match &request.body {
    Some(RequestBody::Memory(data)) => {
        // Handle memory-based body
    }
    Some(RequestBody::File(path)) => {
        // Handle file-based body
    }
    None => {
        // Handle missing body
    }
}
```

### Test Updates

Tests need to be updated to use the new `RequestBody` enum:

```rust
// Before
body: Some(body_data),

// After
body: Some(RequestBody::Memory(body_data)),
```

## Troubleshooting

### Common Issues

1. **Temporary file permissions**: Ensure upload directory is writable
2. **Disk space**: Monitor available disk space for large uploads
3. **Cleanup failures**: Check logs for temporary file cleanup errors

### Debugging

Enable detailed logging to monitor streaming behavior:

```bash
RUST_LOG=debug irondrop --directory /uploads --port 8080
```

### Monitoring

The streaming system integrates with IronDrop's monitoring:

- Upload statistics include both memory and disk uploads
- Performance metrics track processing time for both variants
- Error rates monitor cleanup failures and streaming errors

## Future Enhancements

### Planned Features

1. **Configurable threshold**: Runtime configuration of streaming threshold
2. **Compression support**: Automatic compression for large uploads
3. **Progress tracking**: Real-time progress for disk-streamed uploads
4. **Metrics integration**: Detailed metrics for streaming performance

### Performance Optimizations

1. **Buffer pool**: Reusable buffers for streaming operations
2. **Async I/O**: Non-blocking disk operations for better concurrency
3. **Memory mapping**: Memory-mapped files for very large uploads
4. **Chunked processing**: Streaming processing without temporary files

## Version History

- **v2.7.0**: Direct streaming implementation with unlimited file size support
  - Automatic memory/disk switching based on content size
  - `RequestBody` enum with `Memory` and `File` variants
  - Comprehensive test coverage with dedicated streaming tests
  - Full backward compatibility with existing upload handlers
  - Automatic temporary file cleanup and error handling

## Related Documentation

- [Upload Integration Guide]./UPLOAD_INTEGRATION.md - Upload UI and form handling
- [Multipart Parser Documentation]./MULTIPART_README.md - Multipart form processing
- [API Reference]./API_REFERENCE.md - HTTP API endpoints and responses
- [Architecture Documentation]./ARCHITECTURE.md - Overall system architecture
- [Testing Documentation]./TESTING_DOCUMENTATION.md - Test suite and validation

The HTTP streaming implementation provides a robust foundation for handling uploads of any size while maintaining optimal performance and resource utilization.