fix: update HTTP header constants to use proper capitalization (#186)

- Update all X-Amz-* headers to use capital letters after hyphens (e.g., X-Amz-Date)
  - Update standard HTTP headers to use proper case (e.g., If-Modified-Since)
  - Update X-Minio headers to follow same capitalization pattern
  - Aligns with AWS S3 API specification and HTTP standards
This commit is contained in:
Henk-Jan Lebbink 2025-09-29 14:40:00 +02:00 committed by GitHub
parent 25d424b97f
commit 5a90956db8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 264 additions and 36 deletions

1
AGENTS.md Normal file
View File

@ -0,0 +1 @@
CLAUDE.md

227
CLAUDE.md Normal file
View File

@ -0,0 +1,227 @@
# Claude Code Style Guide for MinIO Rust SDK
- Only provide actionable feedback.
- Exclude code style comments on generated files. These will have a header signifying that.
- Use github markdown folded sections for all items.
- Do not use emojis.
- Do not add a "feel good" section.
## Copyright Header
All source files that haven't been generated MUST include the following copyright header:
```rust
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
// Copyright 20?? MinIO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
```
## Code Style Guidelines
### Ignore files
- Ignore files from processing mentioned under '.gitignore'
### Comments
- **NO redundant comments** - Code should be self-documenting
- Avoid obvious comments like `// Set x to 5` for `x := 5`
- Only add comments when they explain WHY, not WHAT
- Document complex algorithms or non-obvious business logic
## Critical Code Patterns
### Builder Pattern
All S3 API requests MUST use the builder pattern, with the following documentation but then for the appropriate API
```rust
/// Argument builder for the [`AppendObject`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-objects-append.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::append_object`](crate::s3::client::Client::append_object) method.
```
**Key Requirements:**
1. The aws docs url must exist.
### Error Handling Pattern
All Rust SDK methods should follow consistent error handling patterns:
```rust
impl Client {
pub async fn operation_name(&self, args: &OperationArgs) -> Result<OperationResponse, Error> {
// Validate inputs early
args.validate()?;
// Build request
let request = self.build_request(args)?;
// Execute with proper error propagation
let response = self.execute(request).await?;
// Parse and return
OperationResponse::from_response(response)
}
}
```
## Code Quality Principles
### Why Code Quality Standards Are Mandatory
Code quality standards are **critical business requirements** for MinIO Rust SDK:
1. **Enterprise Data Safety**: A single bug can corrupt terabytes of customer data across distributed systems
2. **Code Efficiency**: MinIO Rust SDK code must be efficient and performant
3. **Scalability**: MinIO Rust SDK must be able to handle thousands of concurrent requests
4. **High Availability**: Systems must handle failures gracefully - unpredictable code creates cascading failures
5. **Developer Velocity**: New team members must understand complex distributed systems quickly and safely
### Predictable Code Requirements
Code must exhibit **deterministic behavior** to ensure system reliability:
1. **Managed State**: Use Arc<Mutex<>> or Arc<RwLock<>> for shared state that needs thread-safe access across async operations
2. **Explicit Dependencies**: Business logic dependencies should be passed as parameters or dependency injection
3. **Deterministic Operations**: Avoid time-dependent logic, random values, or platform-specific behavior in core paths
4. **Consistent Error Handling**: Same error conditions must always produce identical error responses
5. **Idempotent Operations**: Operations should be safely repeatable without unintended side effects
### Readability Standards
Complex distributed systems code must remain **human-readable**:
1. **Self-Documenting Code**: Function and variable names should clearly express business intent
2. **Consistent Patterns**: Follow established patterns (HTTP handlers, error handling, logging)
3. **Logical Flow**: Code should read as a clear narrative from top to bottom
4. **Minimal Cognitive Load**: Each function should have a single, well-defined responsibility
5. **Clear Abstractions**: Break complex operations into well-named, focused helper functions
### Separation of Concerns
**Architectural layers must maintain clear boundaries**:
1. **Handler Layer**: HTTP request/response processing, input validation, context creation
2. **Service Layer**: Business logic orchestration, data transformation
3. **Storage Layer**: Data persistence, replication, consistency management
4. **Utility Layer**: Reusable helpers with no business logic dependencies
5. **Shared State Coordination**: Use thread-safe primitives (Arc, Mutex, RwLock) for components needing consistent views
### Functions and Methods
- Keep functions focused on a single responsibility
- Use descriptive names that clearly indicate purpose and business intent
- Prefer early returns to reduce nesting complexity
- Error handling should be immediate and explicit
- **Function length guideline**: Most functions should be under 100 lines; handlers may be longer due to validation logic
- **Parameter limits**: Prefer structs over long parameter lists for better maintainability
### Variables
- Use meaningful variable names that reflect business concepts
- Variable names should reflect usage frequency: frequent variables can be shorter
- Constants should follow Rust patterns
- Global variables should be clearly identified and documented for their system-wide purpose
### Developer Documentation
**All significant features must include developer documentation** in the `docs/` directory:
1. **API Documentation**: New endpoints must have usage examples in `docs/`
2. **Architecture Decisions**: Complex algorithms or design patterns should be documented
3. **Configuration Changes**: New config options must be documented with examples
4. **Integration Guides**: External system integrations need clear setup instructions
5. **Future Developer Context**: Document WHY decisions were made, not just WHAT was implemented
## Testing Requirements
### Why Unit Tests Are Mandatory
Unit tests are **non-negotiable** in this project for critical business reasons:
1. **Data Integrity**: MinIO Rust SDK handles enterprise-critical data. A single bug can cause data loss affecting thousands of users
2. **Security Compliance**: Financial and healthcare customers require verifiable code quality. Tests provide audit trails
3. **Multi-tenant Reliability**: One customer's workload cannot impact another's. Tests ensure proper isolation
4. **Performance SLAs**: Enterprise customers have strict performance requirements. Tests validate behavior under load
5. **API Stability**: Breaking changes can affect thousands of applications. Tests prevent regressions
6. **Distributed System Complexity**: Complex interactions between storage nodes require comprehensive testing
### Mandatory Unit Tests
**EVERY implementation MUST include unit tests** without being explicitly asked. Follow these patterns:
1. Test functions must use `#[test]` or `#[tokio::test]` attributes
2. Use parameterized tests or loop through test cases for multiple scenarios
3. Cover both success and error cases, including edge conditions
4. Mock external dependencies appropriately
5. **Test coverage guideline**: Aim for comprehensive coverage of new code paths
6. Include negative tests for error conditions and boundary cases
7. Add benchmarks for performance-critical code paths
## Improvement Suggestions
Claude will periodically analyze the codebase and suggest:
- Missing test coverage areas
- Performance optimizations
- Code refactoring opportunities
- Security improvements
- Documentation gaps
## Testing Commands
### Pre-commit Checklist
Before any code changes:
1. ✅ Run `cargo fmt --all` to check and fix code formatting
2. ✅ Run `cargo test` to ensure all tests pass
3. ✅ Run `cargo clippy` to check for common mistakes
4. ✅ Ensure new code has appropriate test coverage
5. ✅ Verify no redundant comments are added
## Directory Structure Conventions
- `/src` - Main library source code
- `/tests` - Integration tests
- `/examples` - Example usage code
- `/docs` - Documentation
- `/benches` - Performance benchmarks
## Common Patterns to Follow
### Logging
Use the log crate with appropriate macros:
```rust
use log::{debug, error, info, trace, warn};
// Examples:
info!("Starting operation: {}", operation_name);
debug!("Request details: {:?}", request);
error!("Operation failed: {}", err);
```
### Error Handling
Use the `Result` type with proper error propagation:
```rust
use crate::s3::error::Error;
fn operation() -> Result<Response, Error> {
let result = risky_operation()?;
Ok(process(result))
}
```
## Quick Reference
- **Fix formatting**: `cargo fmt --all`
- **Run tests**: `cargo test`
- **Run specific test**: `cargo test test_name`
- **Check code**: `cargo clippy`
- **Build project**: `cargo build --release`
- **Generate docs**: `cargo doc --open`

View File

@ -13,10 +13,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub const IF_MATCH: &str = "if-match"; pub const IF_MATCH: &str = "If-Match";
pub const IF_NONE_MATCH: &str = "if-none-match"; pub const IF_NONE_MATCH: &str = "If-None-Match";
pub const IF_MODIFIED_SINCE: &str = "if-modified-since"; pub const IF_MODIFIED_SINCE: &str = "If-Modified-Since";
pub const IF_UNMODIFIED_SINCE: &str = "if-unmodified-since"; pub const IF_UNMODIFIED_SINCE: &str = "If-Unmodified-Since";
pub const CONTENT_MD5: &str = "Content-MD5"; pub const CONTENT_MD5: &str = "Content-MD5";
pub const CONTENT_TYPE: &str = "Content-Type"; pub const CONTENT_TYPE: &str = "Content-Type";
pub const AUTHORIZATION: &str = "Authorization"; pub const AUTHORIZATION: &str = "Authorization";
@ -26,61 +26,61 @@ pub const CONTENT_LENGTH: &str = "Content-Length";
pub const POLICY: &str = "policy"; pub const POLICY: &str = "policy";
pub const X_MINIO_DEPLOYMENT_ID: &str = "x-minio-deployment-id"; pub const X_MINIO_DEPLOYMENT_ID: &str = "X-Minio-Deployment-Id";
pub const X_AMZ_VERSION_ID: &str = "x-amz-version-id"; pub const X_AMZ_VERSION_ID: &str = "X-Amz-Version-Id";
pub const X_AMZ_ID_2: &str = "x-amz-id-2"; pub const X_AMZ_ID_2: &str = "X-Amz-Id-2";
pub const X_AMZ_WRITE_OFFSET_BYTES: &str = "x-amz-write-offset-bytes"; pub const X_AMZ_WRITE_OFFSET_BYTES: &str = "X-Amz-Write-Offset-Bytes";
pub const X_AMZ_OBJECT_SIZE: &str = "x-amz-object-size"; pub const X_AMZ_OBJECT_SIZE: &str = "X-Amz-Object-Size";
pub const X_AMZ_TAGGING: &str = "x-amz-tagging"; pub const X_AMZ_TAGGING: &str = "X-Amz-Tagging";
pub const X_AMZ_BUCKET_REGION: &str = "x-amz-bucket-region"; pub const X_AMZ_BUCKET_REGION: &str = "X-Amz-Bucket-Region";
pub const X_AMZ_OBJECT_LOCK_MODE: &str = "x-amz-object-lock-mode"; pub const X_AMZ_OBJECT_LOCK_MODE: &str = "X-Amz-Object-Lock-Mode";
pub const X_AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE: &str = "x-amz-object-lock-retain-until-date"; pub const X_AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE: &str = "X-Amz-Object-Lock-Retain-Until-Date";
pub const X_AMZ_OBJECT_LOCK_LEGAL_HOLD: &str = "x-amz-object-lock-legal-hold"; pub const X_AMZ_OBJECT_LOCK_LEGAL_HOLD: &str = "X-Amz-Object-Lock-Legal-Hold";
pub const X_AMZ_METADATA_DIRECTIVE: &str = "x-amz-metadata-directive"; pub const X_AMZ_METADATA_DIRECTIVE: &str = "X-Amz-Metadata-Directive";
pub const X_AMZ_TAGGING_DIRECTIVE: &str = "x-amz-tagging-directive"; pub const X_AMZ_TAGGING_DIRECTIVE: &str = "X-Amz-Tagging-Directive";
pub const X_AMZ_COPY_SOURCE: &str = "x-amz-copy-source"; pub const X_AMZ_COPY_SOURCE: &str = "X-Amz-Copy-Source";
pub const X_AMZ_COPY_SOURCE_RANGE: &str = "x-amz-copy-source-range"; pub const X_AMZ_COPY_SOURCE_RANGE: &str = "X-Amz-Copy-Source-Range";
pub const X_AMZ_COPY_SOURCE_IF_MATCH: &str = "x-amz-copy-source-if-match"; pub const X_AMZ_COPY_SOURCE_IF_MATCH: &str = "X-Amz-Copy-Source-If-Match";
pub const X_AMZ_COPY_SOURCE_IF_NONE_MATCH: &str = "x-amz-copy-source-if-none-match"; pub const X_AMZ_COPY_SOURCE_IF_NONE_MATCH: &str = "X-Amz-Copy-Source-If-None-Match";
pub const X_AMZ_COPY_SOURCE_IF_UNMODIFIED_SINCE: &str = "x-amz-copy-source-if-unmodified-since"; pub const X_AMZ_COPY_SOURCE_IF_UNMODIFIED_SINCE: &str = "X-Amz-Copy-Source-If-Unmodified-Since";
pub const X_AMZ_COPY_SOURCE_IF_MODIFIED_SINCE: &str = "x-amz-copy-source-if-modified-since"; pub const X_AMZ_COPY_SOURCE_IF_MODIFIED_SINCE: &str = "X-Amz-Copy-Source-If-Modified-Since";
pub const X_AMZ_BUCKET_OBJECT_LOCK_ENABLED: &str = "x-amz-bucket-object-lock-enabled"; pub const X_AMZ_BUCKET_OBJECT_LOCK_ENABLED: &str = "X-Amz-Bucket-Object-Lock-Enabled";
pub const X_AMZ_BYPASS_GOVERNANCE_RETENTION: &str = "x-amz-bypass-governance-retention"; pub const X_AMZ_BYPASS_GOVERNANCE_RETENTION: &str = "X-Amz-Bypass-Governance-Retention";
pub const X_AMZ_DATE: &str = "x-amz-date"; pub const X_AMZ_DATE: &str = "X-Amz-Date";
pub const X_AMZ_DELETE_MARKER: &str = "x-amz-delete-marker"; pub const X_AMZ_DELETE_MARKER: &str = "X-Amz-Delete-Marker";
pub const X_AMZ_ALGORITHM: &str = "x-amz-algorithm"; pub const X_AMZ_ALGORITHM: &str = "X-Amz-Algorithm";
pub const X_AMZ_CREDENTIAL: &str = "x-amz-credential"; pub const X_AMZ_CREDENTIAL: &str = "X-Amz-Credential";
pub const X_AMZ_SIGNATURE: &str = "x-amz-signature"; pub const X_AMZ_SIGNATURE: &str = "X-Amz-Signature";
pub const X_AMZ_REQUEST_ID: &str = "x-amz-request-id"; pub const X_AMZ_REQUEST_ID: &str = "X-Amz-Request-Id";
pub const X_AMZ_EXPIRES: &str = "x-amz-expires"; pub const X_AMZ_EXPIRES: &str = "X-Amz-Expires";
pub const X_AMZ_SIGNED_HEADERS: &str = "x-amz-signedheaders"; pub const X_AMZ_SIGNED_HEADERS: &str = "X-Amz-SignedHeaders";
pub const X_AMZ_CONTENT_SHA256: &str = "x-amz-content-sha256"; pub const X_AMZ_CONTENT_SHA256: &str = "X-Amz-Content-SHA256";
pub const X_AMZ_SECURITY_TOKEN: &str = "x-amz-security-token"; pub const X_AMZ_SECURITY_TOKEN: &str = "X-Amz-Security-Token";
pub const X_AMZ_SERVER_SIDE_ENCRYPTION: &str = "X-Amz-Server-Side-Encryption"; pub const X_AMZ_SERVER_SIDE_ENCRYPTION: &str = "X-Amz-Server-Side-Encryption";

View File

@ -1,7 +1,7 @@
# Set environment variables to run tests on play.min.io # Set environment variables to run tests on play.min.io
$Env:SERVER_ENDPOINT = "http://localhost:9000/" $Env:SERVER_ENDPOINT = "http://localhost:9000/"
$Env:ACCESS_KEY = "minioadmin" $Env:ACCESS_KEY = if ($Env:MINIO_ROOT_USER) { $Env:MINIO_ROOT_USER } else { "minioadmin" }
$Env:SECRET_KEY = "minioadmin" $Env:SECRET_KEY = if ($Env:MINIO_ROOT_PASSWORD) { $Env:MINIO_ROOT_PASSWORD } else { "minioadmin" }
$Env:ENABLE_HTTPS = "false" $Env:ENABLE_HTTPS = "false"
$Env:MINIO_SSL_CERT_FILE = "./tests/public.crt" $Env:MINIO_SSL_CERT_FILE = "./tests/public.crt"
$Env:IGNORE_CERT_CHECK = "false" $Env:IGNORE_CERT_CHECK = "false"