From ace980cff6a22ab0f68e3c9816096e7ad9053dea Mon Sep 17 00:00:00 2001 From: Evan Jarrett Date: Sat, 11 Oct 2025 22:32:13 -0500 Subject: [PATCH] clean up logging, consolidate presigned handlers --- cmd/hold/main.go | 6 +- docs/PRESIGNED_UPLOADS.md | 6 +- pkg/hold/handlers.go | 214 ++++++++------------------------ pkg/hold/s3.go | 6 + pkg/hold/storage.go | 170 +++++++------------------ pkg/hold/types.go | 43 +++---- pkg/storage/proxy_blob_store.go | 38 ++---- 7 files changed, 136 insertions(+), 347 deletions(-) diff --git a/cmd/hold/main.go b/cmd/hold/main.go index a4a27d6..3501606 100644 --- a/cmd/hold/main.go +++ b/cmd/hold/main.go @@ -35,9 +35,9 @@ func main() { mux := http.NewServeMux() mux.HandleFunc("/health", service.HealthHandler) mux.HandleFunc("/register", service.HandleRegister) - mux.HandleFunc("/get-presigned-url", service.HandleGetPresignedURL) - mux.HandleFunc("/head-presigned-url", service.HandleHeadPresignedURL) - mux.HandleFunc("/put-presigned-url", service.HandlePutPresignedURL) + mux.HandleFunc("/get-presigned-url", service.HandlePresignedURL(hold.OperationGet)) + mux.HandleFunc("/head-presigned-url", service.HandlePresignedURL(hold.OperationHead)) + mux.HandleFunc("/put-presigned-url", service.HandlePresignedURL(hold.OperationPut)) mux.HandleFunc("/move", service.HandleMove) // Multipart upload endpoints diff --git a/docs/PRESIGNED_UPLOADS.md b/docs/PRESIGNED_UPLOADS.md index 2989b99..fa8a45b 100644 --- a/docs/PRESIGNED_UPLOADS.md +++ b/docs/PRESIGNED_UPLOADS.md @@ -297,7 +297,7 @@ func (w *ProxyBlobWriter) Cancel(ctx context.Context) error { // Clear buffer to free memory w.buffer = nil - fmt.Printf("❌ [ProxyBlobWriter.Cancel] Upload cancelled: id=%s\n", w.id) + fmt.Printf("[ProxyBlobWriter.Cancel] Upload cancelled: id=%s\n", w.id) return nil } ``` @@ -318,7 +318,7 @@ The current `getUploadURL()` implementation in `cmd/hold/main.go` (lines 528-587 ```go url, err := req.Presign(15 * time.Minute) if err != nil { - log.Printf("❌ Failed to generate presigned upload URL: %v", err) + log.Printf("Failed to generate presigned upload URL: %v", err) return s.getProxyUploadURL(digest, did), nil } @@ -442,7 +442,7 @@ func (s *HoldService) getHeadURL(ctx context.Context, digest string) (string, er url, err := req.Presign(15 * time.Minute) if err != nil { - log.Printf("❌ [getHeadURL] Presign failed: %v", err) + log.Printf("[getHeadURL] Presign failed: %v", err) // Fallback to proxy URL return s.getProxyHeadURL(digest), nil } diff --git a/pkg/hold/handlers.go b/pkg/hold/handlers.go index ce7fad1..56d0efd 100644 --- a/pkg/hold/handlers.go +++ b/pkg/hold/handlers.go @@ -12,157 +12,64 @@ import ( "atcr.io/pkg/atproto" ) -// HandleGetPresignedURL handles requests for download URLs -func (s *HoldService) HandleGetPresignedURL(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) - return - } - - var req GetPresignedURLRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, fmt.Sprintf("invalid request: %v", err), http.StatusBadRequest) - return - } - - log.Printf("📨 [HandleGetPresignedURL] Request received:") - log.Printf(" DID: %s", req.DID) - log.Printf(" Digest: %s", req.Digest) - log.Printf(" Remote: %s", r.RemoteAddr) - log.Printf(" s3Client nil? %v", s.s3Client == nil) - - // Validate DID authorization for READ - if !s.isAuthorizedRead(req.DID) { - log.Printf("❌ [HandleGetPresignedURL] Authorization FAILED") - if req.DID == "" { - // Anonymous request to private hold - http.Error(w, "unauthorized: authentication required", http.StatusUnauthorized) - } else { - // Authenticated but not authorized - http.Error(w, "forbidden: access denied", http.StatusForbidden) +// HandlePresignedURL returns an HTTP handler for presigned URL requests (GET, HEAD, or PUT) +// This consolidates the three separate handlers into a single parameterized implementation +func (s *HoldService) HandlePresignedURL(operation PresignedURLOperation) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return } - return - } - // Generate presigned URL (15 minute expiry) - ctx := context.Background() - expiry := time.Now().Add(15 * time.Minute) - - // For now, construct direct URL to blob - // In production, this would use driver-specific presigned URLs - url, err := s.getDownloadURL(ctx, req.Digest, req.DID) - if err != nil { - log.Printf("❌ [HandleGetPresignedURL] getDownloadURL failed: %v", err) - http.Error(w, fmt.Sprintf("failed to generate URL: %v", err), http.StatusInternalServerError) - return - } - - log.Printf("✅ [HandleGetPresignedURL] Returning URL to client") - - resp := GetPresignedURLResponse{ - URL: url, - ExpiresAt: expiry, - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(resp) -} - -// HandleHeadPresignedURL handles requests for HEAD URLs -func (s *HoldService) HandleHeadPresignedURL(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) - return - } - - var req HeadPresignedURLRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, fmt.Sprintf("invalid request: %v", err), http.StatusBadRequest) - return - } - - log.Printf("📨 [HandleHeadPresignedURL] Request received:") - log.Printf(" DID: %s", req.DID) - log.Printf(" Digest: %s", req.Digest) - log.Printf(" Remote: %s", r.RemoteAddr) - - // Validate DID authorization for READ - if !s.isAuthorizedRead(req.DID) { - log.Printf("❌ [HandleHeadPresignedURL] Authorization FAILED") - if req.DID == "" { - // Anonymous request to private hold - http.Error(w, "unauthorized: authentication required", http.StatusUnauthorized) - } else { - // Authenticated but not authorized - http.Error(w, "forbidden: access denied", http.StatusForbidden) + var req PresignedURLRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, fmt.Sprintf("invalid request: %v", err), http.StatusBadRequest) + return } - return - } - // Generate presigned HEAD URL (15 minute expiry) - ctx := context.Background() - expiry := time.Now().Add(15 * time.Minute) - - url, err := s.getHeadURL(ctx, req.Digest, req.DID) - if err != nil { - log.Printf("❌ [HandleHeadPresignedURL] getHeadURL failed: %v", err) - http.Error(w, fmt.Sprintf("failed to generate URL: %v", err), http.StatusInternalServerError) - return - } - - log.Printf("✅ [HandleHeadPresignedURL] Returning URL to client") - - resp := HeadPresignedURLResponse{ - URL: url, - ExpiresAt: expiry, - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(resp) -} - -// HandlePutPresignedURL handles requests for upload URLs -func (s *HoldService) HandlePutPresignedURL(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) - return - } - - var req PutPresignedURLRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, fmt.Sprintf("invalid request: %v", err), http.StatusBadRequest) - return - } - - // Validate DID authorization for WRITE - if !s.isAuthorizedWrite(req.DID) { - if req.DID == "" { - // Anonymous write attempt - http.Error(w, "unauthorized: authentication required", http.StatusUnauthorized) - } else { - // Authenticated but not crew/owner - http.Error(w, "forbidden: write access denied", http.StatusForbidden) + // Validate DID authorization based on operation type + var authorized bool + switch operation { + case OperationGet, OperationHead: + authorized = s.isAuthorizedRead(req.DID) + case OperationPut: + authorized = s.isAuthorizedWrite(req.DID) + default: + http.Error(w, "unsupported operation", http.StatusBadRequest) + return } - return + + if !authorized { + log.Printf("[HandlePresignedURL:%s] Authorization FAILED", operation) + if req.DID == "" { + http.Error(w, "unauthorized: authentication required", http.StatusUnauthorized) + } else { + http.Error(w, "forbidden: access denied", http.StatusForbidden) + } + return + } + + // Generate presigned URL (15 minute expiry) + ctx := context.Background() + expiry := time.Now().Add(15 * time.Minute) + + url, err := s.getPresignedURL(ctx, operation, req.Digest, req.DID) + if err != nil { + log.Printf("[HandlePresignedURL:%s] getPresignedURL failed: %v", operation, err) + http.Error(w, fmt.Sprintf("failed to generate URL: %v", err), http.StatusInternalServerError) + return + } + + log.Printf("[HandlePresignedURL:%s] Returning URL to client", operation) + + resp := PresignedURLResponse{ + URL: url, + ExpiresAt: expiry, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) } - - // Generate presigned upload URL (15 minute expiry) - ctx := context.Background() - expiry := time.Now().Add(15 * time.Minute) - - url, err := s.getUploadURL(ctx, req.Digest, req.Size, req.DID) - if err != nil { - http.Error(w, fmt.Sprintf("failed to generate URL: %v", err), http.StatusInternalServerError) - return - } - - resp := PutPresignedURLResponse{ - URL: url, - ExpiresAt: expiry, - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(resp) } // HandleProxyGet proxies a blob download through the service @@ -179,11 +86,6 @@ func (s *HoldService) HandleProxyGet(w http.ResponseWriter, r *http.Request) { return } - log.Printf("📥 [HandleProxyGet] Blob download request:") - log.Printf(" Method: %s", r.Method) - log.Printf(" Digest: %s", digest) - log.Printf(" Remote: %s", r.RemoteAddr) - // Get DID from query param or header did := r.URL.Query().Get("did") if did == "" { @@ -193,7 +95,7 @@ func (s *HoldService) HandleProxyGet(w http.ResponseWriter, r *http.Request) { // Authorize READ access if !s.isAuthorizedRead(did) { - log.Printf("❌ [HandleProxyGet] Authorization FAILED") + log.Printf("[HandleProxyGet] Authorization FAILED") if did == "" { http.Error(w, "unauthorized: authentication required", http.StatusUnauthorized) } else { @@ -201,7 +103,6 @@ func (s *HoldService) HandleProxyGet(w http.ResponseWriter, r *http.Request) { } return } - log.Printf("✅ [HandleProxyGet] Authorization SUCCESS") ctx := r.Context() path := blobPath(digest) @@ -290,14 +191,9 @@ func (s *HoldService) HandleProxyPut(w http.ResponseWriter, r *http.Request) { did = r.Header.Get("X-ATCR-DID") } - log.Printf("🔐 [HandleProxyPut] Authorization check:") - log.Printf(" Path: %s", digest) - log.Printf(" DID: %s", did) - log.Printf(" Owner DID: %s", s.config.Registration.OwnerDID) - // Authorize WRITE access if !s.isAuthorizedWrite(did) { - log.Printf("❌ [HandleProxyPut] Authorization FAILED") + log.Printf("[HandleProxyPut] Authorization FAILED") if did == "" { http.Error(w, "unauthorized: authentication required", http.StatusUnauthorized) } else { @@ -306,8 +202,6 @@ func (s *HoldService) HandleProxyPut(w http.ResponseWriter, r *http.Request) { return } - log.Printf("✅ [HandleProxyPut] Authorization SUCCESS") - // Stream blob to storage (no buffering) ctx := r.Context() path := blobPath(digest) diff --git a/pkg/hold/s3.go b/pkg/hold/s3.go index 69d333a..8885988 100644 --- a/pkg/hold/s3.go +++ b/pkg/hold/s3.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "sort" "strings" "time" @@ -158,6 +159,11 @@ func (s *HoldService) completeMultipartUpload(ctx context.Context, digest, uploa s3Key = s.s3PathPrefix + "/" + s3Key } + // Sort parts by part number (S3 requires ascending order) + sort.Slice(parts, func(i, j int) bool { + return parts[i].PartNumber < parts[j].PartNumber + }) + // Convert to S3 CompletedPart format // IMPORTANT: S3 requires ETags to be quoted in the CompleteMultipartUpload XML s3Parts := make([]*s3.CompletedPart, len(parts)) diff --git a/pkg/hold/storage.go b/pkg/hold/storage.go index e094204..5a407f3 100644 --- a/pkg/hold/storage.go +++ b/pkg/hold/storage.go @@ -39,79 +39,24 @@ func blobPath(digest string) string { return fmt.Sprintf("/docker/registry/v2/blobs/%s/%s/%s/data", algorithm, hash[:2], hash) } -// getDownloadURL generates a download URL for a blob -func (s *HoldService) getDownloadURL(ctx context.Context, digest string, did string) (string, error) { - // Check if blob exists +// getPresignedURL generates a presigned URL for GET, HEAD, or PUT operations +func (s *HoldService) getPresignedURL(ctx context.Context, operation PresignedURLOperation, digest string, did string) (string, error) { path := blobPath(digest) - _, err := s.driver.Stat(ctx, path) - if err != nil { - return "", fmt.Errorf("blob not found: %w", err) + + // Check blob exists for GET/HEAD operations (not for PUT since blob doesn't exist yet) + if operation == OperationGet || operation == OperationHead { + if _, err := s.driver.Stat(ctx, path); err != nil { + return "", fmt.Errorf("blob not found: %w", err) + } } - // Check if presigned URLs are disabled for testing + // Check if presigned URLs are disabled if s.config.Server.DisablePresignedURLs { log.Printf("Presigned URLs disabled, using proxy URL") - return s.getProxyDownloadURL(digest, did), nil + return s.getProxyURL(digest, did), nil } - // If S3 client available, generate presigned URL - if s.s3Client != nil { - // Build S3 key from blob path - // blobPath returns paths like: /docker/registry/v2/blobs/sha256/ab/abc123.../data - s3Key := strings.TrimPrefix(path, "/") - if s.s3PathPrefix != "" { - s3Key = s.s3PathPrefix + "/" + s3Key - } - - // Generate presigned GET URL - // Note: Don't use ResponseContentType - not supported by all S3-compatible services - req, _ := s.s3Client.GetObjectRequest(&s3.GetObjectInput{ - Bucket: aws.String(s.bucket), - Key: aws.String(s3Key), - }) - - log.Printf("🔍 [getDownloadURL] Before Presign:") - log.Printf(" Digest: %s", digest) - log.Printf(" S3 Key: %s", s3Key) - log.Printf(" Bucket: %s", s.bucket) - log.Printf(" Request Operation: %s", req.Operation.Name) - log.Printf(" Request HTTPMethod: %s", req.Operation.HTTPMethod) - - url, err := req.Presign(15 * time.Minute) - if err != nil { - log.Printf("❌ [getDownloadURL] Presign FAILED: %v", err) - log.Printf(" Falling back to proxy URL") - return s.getProxyDownloadURL(digest, did), nil - } - - log.Printf("✅ [getDownloadURL] Presigned URL generated successfully") - log.Printf(" URL: %s", url) - log.Printf(" URL Length: %d chars", len(url)) - log.Printf(" Expires: 15min") - - return url, nil - } - - // Fallback: return proxy URL through this service - return s.getProxyDownloadURL(digest, did), nil -} - -// getHeadURL generates a HEAD URL for a blob -func (s *HoldService) getHeadURL(ctx context.Context, digest string, did string) (string, error) { - // Check if blob exists - path := blobPath(digest) - _, err := s.driver.Stat(ctx, path) - if err != nil { - return "", fmt.Errorf("blob not found: %w", err) - } - - // Check if presigned URLs are disabled for testing - if s.config.Server.DisablePresignedURLs { - log.Printf("Presigned URLs disabled, using proxy URL") - return s.getProxyDownloadURL(digest, did), nil - } - - // If S3 client available, generate presigned HEAD URL + // Generate presigned URL if S3 client is available if s.s3Client != nil { // Build S3 key from blob path s3Key := strings.TrimPrefix(path, "/") @@ -119,75 +64,52 @@ func (s *HoldService) getHeadURL(ctx context.Context, digest string, did string) s3Key = s.s3PathPrefix + "/" + s3Key } - // Generate presigned HEAD URL - req, _ := s.s3Client.HeadObjectRequest(&s3.HeadObjectInput{ - Bucket: aws.String(s.bucket), - Key: aws.String(s3Key), - }) + // Create appropriate S3 request based on operation + var req interface { + Presign(time.Duration) (string, error) + } + switch operation { + case OperationGet: + // Note: Don't use ResponseContentType - not supported by all S3-compatible services + req, _ = s.s3Client.GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(s3Key), + }) + case OperationHead: + req, _ = s.s3Client.HeadObjectRequest(&s3.HeadObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(s3Key), + }) + + case OperationPut: + req, _ = s.s3Client.PutObjectRequest(&s3.PutObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(s3Key), + ContentType: aws.String("application/octet-stream"), + }) + + default: + return "", fmt.Errorf("unsupported operation: %s", operation) + } + + // Generate presigned URL with 15 minute expiry url, err := req.Presign(15 * time.Minute) if err != nil { - log.Printf("❌ [getHeadURL] Presign FAILED: %v", err) + log.Printf("[getPresignedURL] Presign FAILED for %s: %v", operation, err) log.Printf(" Falling back to proxy URL") - return s.getProxyDownloadURL(digest, did), nil + return s.getProxyURL(digest, did), nil } - log.Printf("✅ [getHeadURL] Presigned HEAD URL generated: digest=%s", digest) return url, nil } // Fallback: return proxy URL through this service - return s.getProxyDownloadURL(digest, did), nil + return s.getProxyURL(digest, did), nil } -// getProxyDownloadURL returns a proxy URL for blob download (fallback when presigned URLs unavailable) -func (s *HoldService) getProxyDownloadURL(digest, did string) string { - return fmt.Sprintf("%s/blobs/%s?did=%s", s.config.Server.PublicURL, digest, did) -} - -// getUploadURL generates an upload URL for a blob -// Note: This is called from HandlePutPresignedURL which has the DID in the request -func (s *HoldService) getUploadURL(ctx context.Context, digest string, size int64, did string) (string, error) { - // Check if presigned URLs are disabled for testing - if s.config.Server.DisablePresignedURLs { - log.Printf("Presigned URLs disabled, using proxy URL") - return s.getProxyUploadURL(digest, did), nil - } - - // If S3 client available, generate presigned URL - if s.s3Client != nil { - // Build S3 key from blob path - path := blobPath(digest) - s3Key := strings.TrimPrefix(path, "/") - if s.s3PathPrefix != "" { - s3Key = s.s3PathPrefix + "/" + s3Key - } - - // Generate presigned PUT URL with Content-Type in signature - req, _ := s.s3Client.PutObjectRequest(&s3.PutObjectInput{ - Bucket: aws.String(s.bucket), - Key: aws.String(s3Key), - ContentType: aws.String("application/octet-stream"), - }) - - url, err := req.Presign(15 * time.Minute) - if err != nil { - log.Printf("WARN: Presigned URL generation failed for %s, falling back to proxy: %v", digest, err) - return s.getProxyUploadURL(digest, did), nil - } - - log.Printf("🔑 Generated presigned upload URL for %s (expires in 15min)", digest) - log.Printf(" S3 Key: %s", s3Key) - log.Printf(" Bucket: %s", s.bucket) - log.Printf(" Size: %d bytes", size) - return url, nil - } - - // Fallback: return proxy URL through this service - return s.getProxyUploadURL(digest, did), nil -} - -// getProxyUploadURL returns a proxy URL for blob upload (fallback when presigned URLs unavailable) -func (s *HoldService) getProxyUploadURL(digest, did string) string { +// getProxyURL returns a proxy URL for blob operations (fallback when presigned URLs unavailable) +func (s *HoldService) getProxyURL(digest, did string) string { + // All operations use the same proxy endpoint return fmt.Sprintf("%s/blobs/%s?did=%s", s.config.Server.PublicURL, digest, did) } diff --git a/pkg/hold/types.go b/pkg/hold/types.go index 0a5343e..69c875d 100644 --- a/pkg/hold/types.go +++ b/pkg/hold/types.go @@ -4,39 +4,24 @@ import ( "time" ) -// GetPresignedURLRequest represents a request for a presigned download URL -type GetPresignedURLRequest struct { +// PresignedURLOperation defines the type of presigned URL operation +type PresignedURLOperation string + +const ( + OperationGet PresignedURLOperation = "GET" + OperationHead PresignedURLOperation = "HEAD" + OperationPut PresignedURLOperation = "PUT" +) + +// PresignedURLRequest represents a request for a presigned URL (GET, HEAD, or PUT) +type PresignedURLRequest struct { DID string `json:"did"` Digest string `json:"digest"` + Size int64 `json:"size,omitempty"` // Only required for PUT operations } -// GetPresignedURLResponse contains the presigned URL -type GetPresignedURLResponse struct { - URL string `json:"url"` - ExpiresAt time.Time `json:"expires_at"` -} - -// HeadPresignedURLRequest represents a request for a presigned HEAD URL -type HeadPresignedURLRequest struct { - DID string `json:"did"` - Digest string `json:"digest"` -} - -// HeadPresignedURLResponse contains the presigned HEAD URL -type HeadPresignedURLResponse struct { - URL string `json:"url"` - ExpiresAt time.Time `json:"expires_at"` -} - -// PutPresignedURLRequest represents a request for a presigned upload URL -type PutPresignedURLRequest struct { - DID string `json:"did"` - Digest string `json:"digest"` - Size int64 `json:"size"` -} - -// PutPresignedURLResponse contains the presigned upload URL -type PutPresignedURLResponse struct { +// PresignedURLResponse contains the presigned URL +type PresignedURLResponse struct { URL string `json:"url"` ExpiresAt time.Time `json:"expires_at"` } diff --git a/pkg/storage/proxy_blob_store.go b/pkg/storage/proxy_blob_store.go index 30ae04f..21324ff 100644 --- a/pkg/storage/proxy_blob_store.go +++ b/pkg/storage/proxy_blob_store.go @@ -147,42 +147,32 @@ func (p *ProxyBlobStore) Put(ctx context.Context, mediaType string, content []by // Get upload URL url, err := p.getUploadURL(ctx, dgst, int64(len(content))) if err != nil { - fmt.Printf("❌ [proxy_blob_store/Put] Failed to get upload URL: digest=%s, error=%v\n", dgst, err) + fmt.Printf("[proxy_blob_store/Put] Failed to get upload URL: digest=%s, error=%v\n", dgst, err) return distribution.Descriptor{}, err } - fmt.Printf("📤 [proxy_blob_store/Put] Starting PUT request:\n") - fmt.Printf(" Digest: %s\n", dgst) - fmt.Printf(" Size: %d bytes\n", len(content)) - fmt.Printf(" MediaType: %s\n", mediaType) - fmt.Printf(" URL: %s\n", url) - fmt.Printf(" Headers: Content-Type=application/octet-stream\n") - // Upload the blob req, err := http.NewRequestWithContext(ctx, "PUT", url, bytes.NewReader(content)) if err != nil { - fmt.Printf("❌ [proxy_blob_store/Put] Failed to create request: %v\n", err) + fmt.Printf("[proxy_blob_store/Put] Failed to create request: %v\n", err) return distribution.Descriptor{}, err } req.Header.Set("Content-Type", "application/octet-stream") resp, err := p.httpClient.Do(req) if err != nil { - fmt.Printf("❌ [proxy_blob_store/Put] HTTP request failed: %v\n", err) + fmt.Printf("[proxy_blob_store/Put] HTTP request failed: %v\n", err) return distribution.Descriptor{}, err } defer resp.Body.Close() - fmt.Printf("📥 [proxy_blob_store/Put] Response:\n") - fmt.Printf(" Status: %d %s\n", resp.StatusCode, resp.Status) - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { bodyBytes, _ := io.ReadAll(resp.Body) fmt.Printf(" Error Body: %s\n", string(bodyBytes)) return distribution.Descriptor{}, fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(bodyBytes)) } - fmt.Printf("✅ [proxy_blob_store/Put] Upload successful: digest=%s, size=%d\n", dgst, len(content)) + fmt.Printf("[proxy_blob_store/Put] Upload successful: digest=%s, size=%d\n", dgst, len(content)) return distribution.Descriptor{ Digest: dgst, @@ -224,10 +214,6 @@ func (p *ProxyBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter, r // Create returns a blob writer for uploading using multipart upload func (p *ProxyBlobStore) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) { - fmt.Printf("🔧 [proxy_blob_store/Create] Starting multipart upload\n") - fmt.Printf(" Storage endpoint: %s\n", p.storageEndpoint) - fmt.Printf(" Repository: %s\n", p.repository) - // Parse options var opts distribution.CreateOptions for _, option := range options { @@ -624,8 +610,6 @@ func (w *ProxyBlobWriter) flushPart() error { return fmt.Errorf("failed to get part presigned URL: %w", err) } - fmt.Printf("📤 [flushPart] Uploading part %d: size=%d bytes\n", w.partNumber, w.buffer.Len()) - // Upload part to S3 req, err := http.NewRequestWithContext(ctx, "PUT", url, bytes.NewReader(w.buffer.Bytes())) if err != nil { @@ -655,7 +639,7 @@ func (w *ProxyBlobWriter) flushPart() error { ETag: etag, }) - fmt.Printf("✅ [flushPart] Part %d uploaded successfully: ETag=%s\n", w.partNumber, etag) + fmt.Printf("[flushPart] Part %d uploaded successfully: ETag=%s\n", w.partNumber, etag) // Reset buffer and increment part number w.buffer.Reset() @@ -706,8 +690,6 @@ func (w *ProxyBlobWriter) Commit(ctx context.Context, desc distribution.Descript } w.closed = true - fmt.Printf("📝 [Commit] Starting commit: digest=%s, size=%d\n", desc.Digest, w.size) - // Remove from global uploads map globalUploadsMu.Lock() delete(globalUploads, w.id) @@ -715,7 +697,7 @@ func (w *ProxyBlobWriter) Commit(ctx context.Context, desc distribution.Descript // Flush any remaining buffered data if w.buffer.Len() > 0 { - fmt.Printf("📤 [Commit] Flushing final buffer: %d bytes\n", w.buffer.Len()) + fmt.Printf("[Commit] Flushing final buffer: %d bytes\n", w.buffer.Len()) if err := w.flushPart(); err != nil { // Try to abort multipart on error tempDigest := fmt.Sprintf("uploads/temp-%s", w.id) @@ -735,7 +717,7 @@ func (w *ProxyBlobWriter) Commit(ctx context.Context, desc distribution.Descript tempPath := fmt.Sprintf("uploads/temp-%s", w.id) finalPath := desc.Digest.String() - fmt.Printf("🚚 [Commit] Moving blob: %s → %s\n", tempPath, finalPath) + fmt.Printf("[Commit] Moving blob: %s → %s\n", tempPath, finalPath) moveURL := fmt.Sprintf("%s/move?from=%s&to=%s&did=%s", w.store.storageEndpoint, tempPath, finalPath, w.store.did) @@ -755,7 +737,7 @@ func (w *ProxyBlobWriter) Commit(ctx context.Context, desc distribution.Descript return distribution.Descriptor{}, fmt.Errorf("move blob failed: status %d, body: %s", resp.StatusCode, string(bodyBytes)) } - fmt.Printf("✅ [Commit] Upload completed successfully: digest=%s, size=%d, parts=%d\n", desc.Digest, w.size, len(w.parts)) + fmt.Printf("[Commit] Upload completed successfully: digest=%s, size=%d, parts=%d\n", desc.Digest, w.size, len(w.parts)) return distribution.Descriptor{ Digest: desc.Digest, @@ -768,7 +750,7 @@ func (w *ProxyBlobWriter) Commit(ctx context.Context, desc distribution.Descript func (w *ProxyBlobWriter) Cancel(ctx context.Context) error { w.closed = true - fmt.Printf("❌ [Cancel] Cancelling upload: id=%s\n", w.id) + fmt.Printf("[Cancel] Cancelling upload: id=%s\n", w.id) // Remove from global uploads map globalUploadsMu.Lock() @@ -782,7 +764,7 @@ func (w *ProxyBlobWriter) Cancel(ctx context.Context) error { // Continue anyway - we want to mark upload as cancelled } - fmt.Printf("✅ [Cancel] Upload cancelled: id=%s\n", w.id) + fmt.Printf("[Cancel] Upload cancelled: id=%s\n", w.id) return nil }