zeroshade commented on code in PR #458:
URL: https://github.com/apache/iceberg-go/pull/458#discussion_r3439200773


##########
io/s3.go:
##########
@@ -149,3 +201,175 @@ func createS3Bucket(ctx context.Context, parsed *url.URL, 
props map[string]strin
 
        return bucket, nil
 }
+
+// RemoteSigningRequest represents the request sent to the remote signer
+type RemoteSigningRequest struct {
+       Method  string            `json:"method"`
+       URI     string            `json:"uri"`
+       Headers map[string]string `json:"headers,omitempty"`
+       Region  string            `json:"region"`
+}
+
+// RemoteSigningResponse represents the response from the remote signer
+type RemoteSigningResponse struct {
+       Headers map[string]string `json:"headers"`
+}
+
+// remoteSigningTransport wraps an HTTP transport to handle remote signing
+type remoteSigningTransport struct {
+       base      http.RoundTripper
+       signerURI string
+       region    string
+       authToken string
+       client    *http.Client
+}
+
+// newRemoteSigningTransport creates a new remote signing transport
+func newRemoteSigningTransport(base http.RoundTripper, signerURI, region, 
authToken string) *remoteSigningTransport {
+       return &remoteSigningTransport{
+               base:      base,
+               signerURI: signerURI,
+               region:    region,
+               authToken: authToken,
+               client: &http.Client{
+                       Timeout: 30 * time.Second,
+               },
+       }
+}
+
+// RoundTrip implements http.RoundTripper
+func (r *remoteSigningTransport) RoundTrip(req *http.Request) (*http.Response, 
error) {
+       // Only handle S3 requests
+       if !r.isS3Request(req) {
+               return r.base.RoundTrip(req)
+       }
+
+       // Get signed headers from remote signer
+       signedHeaders, err := r.getRemoteSignature(req.Context(), req.Method, 
req.URL.String(), r.extractHeaders(req))
+       if err != nil {
+               fmt.Printf("\033[31m%s\033[0m\n", err.Error()) // fails silently
+               return nil, fmt.Errorf("failed to get remote signature: %w", 
err)
+       }
+
+       // Clone the request and apply signed headers
+       newReq := req.Clone(req.Context())
+       for key, value := range signedHeaders {
+               newReq.Header.Set(key, value)
+       }
+
+       return r.base.RoundTrip(newReq)
+}
+
+// isS3Request checks if the request is destined for S3
+func (r *remoteSigningTransport) isS3Request(req *http.Request) bool {
+       // Check if the host contains typical S3 patterns
+       host := req.URL.Host
+
+       // Don't sign requests to the remote signer itself to avoid circular 
dependency
+       if r.signerURI != "" {
+               signerHost := ""
+               if signerURL, err := url.Parse(r.signerURI); err == nil {
+                       signerHost = signerURL.Host
+               }
+               if host == signerHost {
+                       return false
+               }
+       }
+
+       result := host != "" && (
+       // Standard S3 endpoints
+       host == "s3.amazonaws.com" ||
+               // Regional S3 endpoints
+               (len(host) > 12 && host[len(host)-12:] == ".amazonaws.com" && 
(host[:3] == "s3." || host[len(host)-17:len(host)-12] == ".s3")) ||
+               // Virtual hosted-style bucket access
+               (len(host) > 17 && host[len(host)-17:] == ".s3.amazonaws.com") 
||
+               // Path-style access to S3
+               (len(host) > 3 && host[:3] == "s3.") ||
+               // Cloudflare R2 endpoints
+               (len(host) > 20 && host[len(host)-20:] == 
".r2.cloudflarestorage.com") ||
+               // MinIO or other custom S3-compatible endpoints (be more 
conservative)
+               (len(host) > 0 && (host == "localhost:9000" || host == 
"127.0.0.1:9000" ||
+                       // Only sign if it looks like an S3 request pattern 
(has bucket-like structure)
+                       // and is NOT a catalog service (which typically has 
/catalog/ in the path)
+                       (req.URL.Path != "" && !strings.Contains(req.URL.Path, 
"/catalog/") &&
+                               !strings.Contains(host, "catalog") &&
+                               // Exclude common non-S3 service patterns
+                               !strings.Contains(host, "glue.") &&
+                               !strings.Contains(host, "api.") &&
+                               !strings.Contains(host, "catalog.")))))

Review Comment:
   Let's put it into a utils.go file



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to