This document describes MinIO's implementation of the Amazon S3-compatible HTTP API, covering request routing, handler architecture, authentication flow, object and bucket operations, error handling, and response generation. The S3 API layer serves as the primary interface for client applications, translating HTTP requests into internal storage operations.
Related Documentation:
The S3 API implementation is the HTTP interface layer that translates S3-compatible requests into internal storage operations.
Sources: cmd/api-router.go67-70 cmd/object-handlers.go68-70 cmd/routers.go54-81 cmd/generic-handlers.go54-81
The objectAPIHandlers struct cmd/object-handlers.go68-70 provides access to the storage layer through its ObjectAPI function field, which returns the active ObjectLayer implementation.
Handler Categories:
| Category | Key Handlers | Storage Layer Method | Code Location |
|---|---|---|---|
| Object Read | GetObjectHandler, HeadObjectHandler, GetObjectAttributesHandler | GetObjectNInfo, GetObjectInfo | cmd/object-handlers.go717 cmd/object-handlers.go1012 cmd/object-handlers.go988 |
| Object Write | PutObjectHandler, CopyObjectHandler, PostObjectHandler | PutObject, CopyObject | cmd/object-handlers.go1547 cmd/object-handlers.go1037 cmd/object-handlers.go4201 |
| Object Delete | DeleteObjectHandler | DeleteObject | cmd/object-handlers.go2316 |
| Bucket Ops | ListBucketsHandler, PutBucketHandler, DeleteBucketHandler, HeadBucketHandler | ListBuckets, MakeBucket, DeleteBucket, GetBucketInfo | cmd/bucket-handlers.go305 cmd/bucket-handlers.go720 cmd/bucket-handlers.go922 |
| Bucket List | ListObjectsV2Handler, ListObjectsV1Handler, ListObjectVersionsHandler | ListObjects, ListObjectVersions | cmd/bucket-handlers.go1295 cmd/bucket-handlers.go1008 |
| Multipart | NewMultipartUploadHandler, PutObjectPartHandler, CompleteMultipartUploadHandler, AbortMultipartUploadHandler, ListObjectPartsHandler | NewMultipartUpload, PutObjectPart, CompleteMultipartUpload, AbortMultipartUpload, ListObjectParts | cmd/object-handlers.go2456 cmd/object-handlers.go2717 cmd/object-handlers.go3055 cmd/object-handlers.go3666 cmd/object-handlers.go3737 |
| S3 Select | SelectObjectContentHandler | GetObjectNInfo with SQL filtering | cmd/object-handlers.go105 |
| Batch Delete | DeleteMultipleObjectsHandler | DeleteObjects | cmd/bucket-handlers.go413 |
Standard Handler Pattern:
api.ObjectAPI() to get storage interface cmd/object-handlers.go722-726mux.Vars(r) cmd/object-handlers.go728-734checkRequestAuthType() or authenticateRequest() cmd/object-handlers.go327-358getOpts() cmd/object-handlers.go319-323ObjectLayer method with parsed parameterswriteSuccessResponseXML() or writeErrorResponse()Sources: cmd/object-handlers.go68-70 cmd/object-handlers.go105-4687 cmd/bucket-handlers.go200-1480
Routes are registered in registerAPIRouter() cmd/api-router.go207-596 using the mux.Router from the github.com/minio/mux package.
Sources: cmd/routers.go84-94 cmd/api-router.go207-596
Object Routes (/{bucket}/{object:.+} from cmd/api-router.go413-596):
| HTTP Method | Query Params | Handler | Code Location |
|---|---|---|---|
| GET | - | GetObjectHandler | cmd/object-handlers.go717 |
| GET | attributes | GetObjectAttributesHandler | cmd/object-handlers.go988 |
| GET | legal-hold | GetObjectLegalHoldHandler | cmd/object-handlers.go2196 |
| GET | retention | GetObjectRetentionHandler | cmd/object-handlers.go2095 |
| GET | tagging | GetObjectTaggingHandler | cmd/object-handlers.go4005 |
| GET | acl | GetObjectACLHandler | cmd/object-handlers.go3901 |
| GET | select, select-type=2 | SelectObjectContentHandler | cmd/object-handlers.go105 |
| HEAD | - | HeadObjectHandler | cmd/object-handlers.go1012 |
| PUT | - | PutObjectHandler | cmd/object-handlers.go1547 |
| PUT | legal-hold | PutObjectLegalHoldHandler | cmd/object-handlers.go2242 |
| PUT | retention | PutObjectRetentionHandler | cmd/object-handlers.go2138 |
| PUT | tagging | PutObjectTaggingHandler | cmd/object-handlers.go4048 |
| PUT | acl | PutObjectACLHandler | cmd/object-handlers.go3985 |
| DELETE | - | DeleteObjectHandler | cmd/object-handlers.go2316 |
| DELETE | tagging | DeleteObjectTaggingHandler | cmd/object-handlers.go4128 |
| POST | restore | PostRestoreObjectHandler | cmd/object-handlers.go4161 |
| POST | - | PostObjectHandler (form upload) | cmd/object-handlers.go4201 |
Bucket Routes (/{bucket} from cmd/api-router.go299-412):
| HTTP Method | Query Params | Handler | Code Location |
|---|---|---|---|
| GET | list-type=2 | ListObjectsV2Handler | cmd/bucket-handlers.go1295 |
| GET | - | ListObjectsV1Handler | cmd/bucket-handlers.go1008 |
| GET | versions | ListObjectVersionsHandler | cmd/bucket-handlers.go1482 |
| GET | location | GetBucketLocationHandler | cmd/bucket-handlers.go203 |
| GET | uploads | ListMultipartUploadsHandler | cmd/bucket-handlers.go250 |
| GET | versioning | GetBucketVersioningHandler | cmd/bucket-handlers.go2230 |
| GET | policy | GetBucketPolicyHandler | cmd/bucket-handlers.go1793 |
| GET | tagging | GetBucketTaggingHandler | cmd/bucket-handlers.go2042 |
| GET | object-lock | GetBucketObjectLockConfigHandler | cmd/bucket-handlers.go2284 |
| GET | lifecycle | GetBucketLifecycleHandler | cmd/bucket-handlers.go1867 |
| GET | replication | GetBucketReplicationConfigHandler | cmd/bucket-handlers.go2387 |
| GET | encryption | GetBucketEncryptionHandler | cmd/bucket-handlers.go2156 |
| PUT | - | PutBucketHandler | cmd/bucket-handlers.go720 |
| PUT | versioning | PutBucketVersioningHandler | cmd/bucket-handlers.go2247 |
| PUT | policy | PutBucketPolicyHandler | cmd/bucket-handlers.go1703 |
| PUT | tagging | PutBucketTaggingHandler | cmd/bucket-handlers.go2074 |
| PUT | object-lock | PutBucketObjectLockConfigHandler | cmd/bucket-handlers.go2301 |
| PUT | lifecycle | PutBucketLifecycleHandler | cmd/bucket-handlers.go1898 |
| PUT | replication | PutBucketReplicationConfigHandler | cmd/bucket-handlers.go2494 |
| PUT | encryption | PutBucketEncryptionHandler | cmd/bucket-handlers.go2193 |
| DELETE | - | DeleteBucketHandler | cmd/bucket-handlers.go922 |
| DELETE | policy | DeleteBucketPolicyHandler | cmd/bucket-handlers.go1771 |
| DELETE | tagging | DeleteBucketTaggingHandler | cmd/bucket-handlers.go2116 |
| DELETE | lifecycle | DeleteBucketLifecycleHandler | cmd/bucket-handlers.go1851 |
| DELETE | replication | DeleteBucketReplicationConfigHandler | cmd/bucket-handlers.go2375 |
| DELETE | encryption | DeleteBucketEncryptionHandler | cmd/bucket-handlers.go2140 |
| POST | delete | DeleteMultipleObjectsHandler | cmd/bucket-handlers.go413 |
| HEAD | - | HeadBucketHandler | cmd/bucket-handlers.go1655 |
Root Routes (/ from cmd/api-router.go226-241):
| HTTP Method | Query Params | Handler | Code Location |
|---|---|---|---|
| GET | - | ListBucketsHandler | cmd/bucket-handlers.go305 |
Route Registration Pattern cmd/api-router.go299-412:
Routes are registered using a fluent API with method chaining:
Key components:
.Methods(http.MethodGet): Specifies HTTP method (GET, PUT, POST, DELETE, HEAD).HandlerFunc(...): Wraps handler with s3APIMiddleware for metrics, tracing, compression.Queries("key", "value"): Matches query parameters to distinguish operations on same pathnoGZS3HFlag disables compression, traceHdrsS3HFlag traces headers only, noThrottleS3HFlag disables request throttlingThe .Queries() method is critical for operation disambiguation when multiple S3 operations share the same HTTP method and path but differ by query parameters.
Sources: cmd/api-router.go207-596 cmd/object-handlers.go105-4687 cmd/bucket-handlers.go200-1480
Requests flow through the globalMiddlewares slice cmd/routers.go54-81 and handler-specific middleware from s3APIMiddleware() cmd/api-router.go171-205
Sources: cmd/routers.go54-81 cmd/api-router.go171-205 cmd/generic-handlers.go109-472
addCustomHeadersMiddleware (from globalMiddlewares list):
x-amz-request-id using mustGetRequestID() for request trackingx-amz-id-2 with deployment ID from globalDeploymentID()httpTracerMiddleware (from globalMiddlewares list):
mcontext.TraceCtxt for structured loggingmcontext.ContextTraceKey in request contextsetAuthMiddleware (from globalMiddlewares list):
Authorization header to extract credentialsReqInfo.Cred with parsed credentials for downstream handlerssetRequestLimitMiddleware (from globalMiddlewares list):
X-Minio-Internal-)http.MaxBytesReader(w, r.Body, requestMaxBodySize)ErrMetadataTooLarge or ErrUnsupportedMetadata on violationssetRequestValidityMiddleware (from globalMiddlewares list):
Host header format using hasBadHost()., ..) via hasBadPathComponent()s3utils.CheckValidBucketNameStrict()hasMultipleAuth()setUploadForwardingMiddleware (from globalMiddlewares list):
setBucketForwardingMiddleware (from globalMiddlewares list):
globalDNSConfig for bucket locations3APIMiddleware (handler-level wrapper):
globalHTTPStats, measures latency503 SlowDown on overflowAccept-Encoding: gzip presentnoGZS3HFlag, traceHdrsS3HFlag, noThrottleS3HFlagSources: cmd/generic-handlers.go46-472 cmd/routers.go54-81 cmd/api-router.go171-205
Each handler calls checkRequestAuthType() or authenticateRequest() to verify credentials and check IAM permissions.
Sources: cmd/auth-handler.go1-300 cmd/iam.go214-287
| Auth Type | Header/Query | Detection | Validation Function |
|---|---|---|---|
| AWS Sig V4 | Authorization: AWS4-HMAC-SHA256... | isRequestSignatureV4() | validateV4Signature() |
| Presigned V4 | X-Amz-Signature query param | isRequestPresignedSignatureV4() | validateV4Signature() |
| AWS Sig V2 | Authorization: AWS ... | isRequestSignatureV2() | validateV2Signature() |
| Presigned V2 | Signature query param | isRequestPresignedSignatureV2() | validateV2Signature() |
| STS Token | X-Amz-Security-Token header | isRequestJWT() | JWT token validation |
| Anonymous | No credentials | authTypeAnonymous | Bucket policy only |
Validation Steps (from cmd/auth-handler.go1-300):
getRequestAuthType(r) to identify auth methodglobalIAMSys.GetUser(accessKey)globalIAMSys.IsAllowed(policy.Args{...})ErrNone for success, ErrAccessDenied/ErrSignatureDoesNotMatch for failureThe checkRequestAuthType() function cmd/auth-handler.go1-300 combines all steps and returns an APIErrorCode.
Sources: cmd/auth-handler.go1-300 cmd/iam.go214-287
Sources: cmd/object-handlers.go313-578
GetObjectHandler Flow cmd/object-handlers.go313-578:
s3:GetObject permission via authenticateRequest()Range header for partial reads (HTTP 206)opts.CheckPrecondFn to decrypt metadata and re-authorize with tagsobjectAPI.GetObjectNInfo() to obtain streaming readerxioutil.Copy() to stream object data to clientObjectAccessedGet eventConditional Request Support:
Sources: cmd/object-handlers.go313-578
Sources: cmd/object-handlers.go900-1500
PutObjectHandler Processing cmd/object-handlers.go900-1500:
s3:PutObject permissionx-amz-storage-class header (STANDARD or REDUCED_REDUNDANCY)x-amz-server-side-encryption: AES256), SSE-KMS (aws:kms), or SSE-C (customer-provided key)x-amz-object-lock-mode and x-amz-object-lock-retain-until-date for retention, x-amz-object-lock-legal-hold for legal holdobjectAPI.PutObject() which triggers erasure codingObjectCreated:Put event to configured targetsMetadata Handling cmd/object-handlers.go310-325:
x-amz-meta- (maximum 2KB total size)x-amz-tagging header (up to 10 tags, 128 char keys, 256 char values)Sources: cmd/object-handlers.go900-1500 cmd/object-handlers.go310-325
Sources: cmd/object-handlers.go1800-2000
DeleteObjectHandler Logic cmd/object-handlers.go1800-2000:
s3:DeleteObject or s3:DeleteObjectVersion permissionversionId query parameter if presentx-amz-version-id (version deleted or delete marker created), x-amz-delete-marker (true/false)ObjectRemoved:Delete or ObjectRemoved:DeleteMarkerCreated eventSources: cmd/object-handlers.go1800-2000
HeadObjectHandler cmd/object-handlers.go2200-2400:
Returns all object metadata without transferring the object body:
s3:GetObject permissionobjectAPI.GetObjectInfo() to fetch object metadataResponse Headers (from setObjectHeaders() cmd/object-api-utils.go1015-1262):
Content-Length: Object size in bytesContent-Type: MIME type from metadata or binary/octet-stream defaultETag: Object checksum (MD5 for non-encrypted, format varies for encrypted/multipart)Last-Modified: Last modification time in RFC 1123 formatx-amz-version-id: Version ID if versioning enabledx-amz-server-side-encryption-*: Encryption headers (algorithm, key ID, context)x-amz-object-lock-mode: Retention mode (GOVERNANCE or COMPLIANCE)x-amz-object-lock-retain-until-date: Retention expiry datex-amz-object-lock-legal-hold: Legal hold status (ON or OFF)x-amz-tagging-count: Number of tags attached to objectx-amz-meta-*: All user-defined metadata headersCache-Control, Content-Encoding, Content-Language, Content-Disposition: Standard HTTP headersx-amz-replication-status: Replication status if applicablex-amz-storage-class: Storage class (STANDARD, REDUCED_REDUNDANCY, GLACIER, etc.)Sources: cmd/object-handlers.go746-983 cmd/object-api-utils.go1015-1262
Multipart upload enables uploading large objects in independent parts, supporting parallel uploads and failure recovery.
Sources: cmd/object-handlers.go2600-4000
NewMultipartUploadHandler cmd/object-handlers.go2600-2800:
<UploadId>xyz</UploadId>PutObjectPartHandler cmd/object-handlers.go2900-3200:
.minio.sys/tmp/uploadId/partNumber)CompleteMultipartUploadHandler cmd/object-handlers.go3300-3500:
{partETag1}-{partCount})AbortMultipartUploadHandler cmd/object-handlers.go3600-3700:
ListMultipartUploadsHandler cmd/bucket-handlers.go243-293:
key-marker and upload-id-marker<ListMultipartUploadsResult>ListObjectPartsHandler cmd/object-handlers.go3800-4000:
part-number-marker<ListPartsResult>Sources: cmd/object-handlers.go2600-4000 cmd/bucket-handlers.go243-293
| Handler | HTTP Method | Purpose | Key Functionality |
|---|---|---|---|
ListBucketsHandler | GET / | List all buckets | Returns bucket names and creation dates |
HeadBucketHandler | HEAD /{bucket} | Check bucket exists | Returns 200 if exists, 404 if not |
GetBucketLocationHandler | GET /{bucket}?location | Get bucket region | Returns region (empty for MinIO) |
PutBucketHandler | PUT /{bucket} | Create bucket | Creates bucket, validates DNS, initializes versioning |
DeleteBucketHandler | DELETE /{bucket} | Delete bucket | Removes empty bucket, fails if non-empty |
ListObjectsV1Handler | GET /{bucket}?delimiter= | List objects v1 | Legacy listing with marker-based pagination |
ListObjectsV2Handler | GET /{bucket}?list-type=2 | List objects v2 | Modern listing with continuation token |
GetBucketVersioningHandler | GET /{bucket}?versioning | Get versioning status | Returns Enabled/Suspended/not set |
PutBucketVersioningHandler | PUT /{bucket}?versioning | Enable versioning | Enables or suspends versioning |
GetBucketPolicyHandler | GET /{bucket}?policy | Get bucket policy | Returns IAM policy JSON |
PutBucketPolicyHandler | PUT /{bucket}?policy | Set bucket policy | Validates and applies IAM policy |
Sources: cmd/bucket-handlers.go1-1500
Sources: cmd/bucket-handlers.go800-1100
ListObjectsV2Handler cmd/bucket-handlers.go800-1100:
Query Parameters:
prefix: Filter objects starting with this prefixdelimiter: Group keys by common prefix (typically / for directory simulation)max-keys: Maximum objects to return (default 1000, max 1000)continuation-token: Opaque token to resume listing from previous pagestart-after: Begin listing after this key lexicographicallyfetch-owner: Include owner information (MinIO extension)Response Structure:
Performance Optimization: Uses metacache system to cache directory listings, significantly accelerating repeated list operations. Cache invalidated on write operations.
Sources: cmd/bucket-handlers.go800-1100
MinIO converts internal errors to S3-compatible error responses using the errorCodes map cmd/api-errors.go482-1400
Errors are returned as XML via writeErrorResponse() cmd/api-response.go644-719:
| Error Code | HTTP Status | Condition |
|---|---|---|
NoSuchKey | 404 | Object does not exist |
NoSuchBucket | 404 | Bucket does not exist |
NoSuchUpload | 404 | Multipart upload ID not found |
AccessDenied | 403 | Authentication failed or insufficient permissions |
InvalidAccessKeyId | 403 | Access key not found in IAM system |
SignatureDoesNotMatch | 403 | Request signature validation failed |
InvalidDigest | 400 | Content-MD5 header does not match computed MD5 |
EntityTooLarge | 400 | Object size exceeds maximum (5TB) |
EntityTooSmall | 400 | Object smaller than minimum for operation |
InvalidArgument | 400 | Invalid parameter value |
InvalidBucketName | 400 | Bucket name violates naming rules |
MethodNotAllowed | 405 | HTTP method not supported for resource |
PreconditionFailed | 412 | Conditional request failed |
InternalError | 500 | Server-side error |
ServiceUnavailable | 503 | Server temporarily overloaded or maintenance |
Sources: cmd/api-errors.go84-250
Sources: cmd/object-api-errors.go30-300 cmd/api-errors.go482-1400 cmd/api-response.go644-719
Error Translation Steps:
ObjectNotFound{} from cmd/object-api-errors.go301-421)toAPIError(ctx, err) cmd/object-api-errors.go30-300 which maps errors to APIErrorCodeerrorCodes.ToAPIErr(code) cmd/api-errors.go476-478 to get APIError struct with HTTP status and messagewriteErrorResponse() cmd/api-response.go644-719 to marshal XML and write to clientError Code Examples cmd/api-errors.go84-455:
ErrNoSuchKey (404): Object does not existErrNoSuchBucket (404): Bucket does not existErrAccessDenied (403): Insufficient permissionsErrSignatureDoesNotMatch (403): Invalid request signatureErrInvalidDigest (400): Content-MD5 mismatchErrInternalError (500): Unexpected server errorAPIErrorResponse Fields cmd/api-errors.go64-76:
Code: S3 error code stringMessage: Human-readable descriptionRequestID: From x-amz-request-id headerHostID: From x-amz-id-2 headerResource, BucketName, Key: Request contextSources: cmd/object-api-errors.go30-421 cmd/api-errors.go54-1400 cmd/api-response.go644-719
Common Response Headers (set by setObjectHeaders() cmd/object-api-utils.go1015-1262):
| Header | Purpose | Example |
|---|---|---|
Content-Type | MIME type | image/jpeg |
Content-Length | Object size | 1048576 |
ETag | Object checksum | "5d41402abc4b2a76b9719d911017c592" |
Last-Modified | Modification time | Wed, 15 Nov 2023 12:00:00 GMT |
x-amz-version-id | Version ID | NjhkNDQ5M2EtY2U3NC00 |
x-amz-request-id | Request ID | F2A8BABEEC3F |
x-amz-id-2 | Deployment ID | From globalDeploymentID() |
Encryption Headers (from cmd/object-handlers.go506-521):
x-amz-server-side-encryption: AES256 (SSE-S3) or aws:kms (SSE-KMS)x-amz-server-side-encryption-aws-kms-key-id: KMS key IDx-amz-server-side-encryption-customer-algorithm: SSE-C algorithmx-amz-server-side-encryption-customer-key-md5: SSE-C key MD5Object Lock Headers (from cmd/object-handlers.go210-216):
x-amz-object-lock-mode: GOVERNANCE or COMPLIANCEx-amz-object-lock-retain-until-date: Retention expiry (ISO 8601)x-amz-object-lock-legal-hold: ON or OFFReplication Headers:
x-amz-replication-status: PENDING, COMPLETED, FAILED, REPLICAx-amz-delete-marker: true or falseSources: cmd/object-api-utils.go1015-1262 cmd/object-handlers.go210-216 cmd/object-handlers.go506-521
writeSuccessResponseXML() cmd/api-response.go721-737:
encodeResponse()Content-Type: application/xmlhttp.ResponseWriterencodeResponse() cmd/api-response.go739-772:
xxml.Marshal()[]byte for writingsetObjectHeaders() cmd/object-api-utils.go1015-1262:
writeErrorResponse() cmd/api-response.go644-719:
APIError to XMLAPIError.HTTPStatusCodeSources: cmd/api-response.go644-772 cmd/object-api-utils.go1015-1262
CopyObjectHandler cmd/object-handlers.go1600-1800:
Copies objects entirely server-side without client download/upload:
x-amz-copy-source headers3:GetObject on source, s3:PutObject on destinationCOPY: Preserve original object metadataREPLACE: Use metadata from copy request headersx-amz-copy-source-range for partial object copyUse Cases:
REPLACE directive)Sources: cmd/object-handlers.go1600-1800
SelectObjectContentHandler cmd/object-handlers.go100-311:
Execute SQL queries directly on objects without downloading:
s3select package to parse and execute SQLSupported SQL:
SELECT with column selection and wildcard (*)WHERE clauses with comparison operatorsCOUNT, SUM, AVG, MIN, MAXLIMIT clause for row limitingSources: cmd/object-handlers.go100-311
Presigned URLs provide temporary authenticated access without exposing credentials.
Client-Side Generation:
Server-Side Validation cmd/handler-utils.go200-400:
X-Amz-Signature query parameterX-Amz-Date and X-Amz-Expires parametersErrExpiredPresignRequest if expiredSources: cmd/handler-utils.go200-400
PostObjectHandler cmd/object-handlers.go4200-4600:
Supports browser-based uploads via HTML forms:
success_action_redirect URL or return success_action_status codePolicy Conditions:
bucket: Exact bucket namekey: Object key (supports ${filename} variable)content-length-range: Min and max sizex-amz-*: Metadata and header constraintsSources: cmd/object-handlers.go4200-4600
globalInternodeTransport cmd/globals.go100-200:
MaxIdleConnsPerHost for connection reusegzhttp.GzipHandler cmd/api-router.go50-100:
Accept-Encoding: gzipmaxClients() cmd/generic-handlers.go400-450:
Metacache System:
ListObjects operationsSources: cmd/globals.go100-200 cmd/api-router.go50-100 cmd/generic-handlers.go400-450
MinIO's S3 API implementation provides comprehensive Amazon S3 compatibility through a well-structured handler architecture:
Core Architecture:
objectAPIHandlers with methods for all S3 operationsObjectLayer abstraction decouples API from storage implementationKey Operations:
Cross-Cutting Concerns:
The implementation maintains strict S3 API compatibility while leveraging MinIO's distributed erasure-coded storage for high availability and data durability.
Sources: cmd/object-handlers.go1-4600 cmd/bucket-handlers.go1-1500 cmd/api-router.go1-500 cmd/api-errors.go1-1500 cmd/api-response.go1-500 cmd/generic-handlers.go1-500 cmd/handler-utils.go1-500
Refresh this wiki