Skip to content

AWS, Core: Read S3 files via catalog-vended HTTPS URLs - #17457

Open
williamhyun wants to merge 4 commits into
apache:mainfrom
williamhyun:s3-presign-url
Open

AWS, Core: Read S3 files via catalog-vended HTTPS URLs#17457
williamhyun wants to merge 4 commits into
apache:mainfrom
williamhyun:s3-presign-url

Conversation

@williamhyun

@williamhyun williamhyun commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary

Adds support for reading object-store files over catalog-vended HTTP(S) URLs without requiring native cloud credentials on the reader, and wires it into S3FileIO.

  • Core: Introduces HttpUrlSupport, HTTPInputFile, and HTTPInputStream — a seekable, range-readable HTTP(S) input path built on the httpclient5 dependency iceberg-core already depends on (also used by org.apache.iceberg.rest.HTTPClient), so no new third-party dependency is added. Reads are served via chunked range GETs (4 MB chunks), with retries on transient network/server errors during those range fetches; content length is probed via Range: bytes=0-0 when unknown, since pre-signed GET URLs typically reject HEAD.
  • AWS: S3FileIO#newInputFile(String) / newInputFile(String, long) now short-circuit to HttpUrlSupport when the location is an http:// or https:// URL, leaving s3:///s3a:///s3n:// reads on the native, credentialed S3 client path unchanged. S3FileIO#close() now also closes the shared HTTP client.
  • Tests: Unit coverage for the dispatch decision (TestS3FileIOHttpUrlDispatch) and for HTTPInputFile/HTTPInputStream behavior against a real local HttpServer (TestHTTPInputFile, including multi-chunk reads that cross the 4 MB boundary); a MinIO-backed integration test (TestS3FileIOPresignedUrls) that mints real pre-signed URLs and proves the native S3 client is never invoked; and an optional live-AWS integration test (TestS3FileIOLivePresignedUrls) gated on AWS credential env vars.
    This is the FileIO building block for catalogs that vend a pre-signed URL as a file's file-path in scan planning, so readers can fetch bytes over HTTPS with auth encoded in the URL itself. Delete-file handling, scan-planning integration, and other cloud providers are out of scope for this PR (see below).

Scope / compatibility notes

  1. The catalog is expected to place a usable, already-signed URL directly in the file's location (file-path); the client uses that location unchanged as the fetch URL. There is no separate signing lookup or location-to-URL mapping in this PR.
  2. Only S3FileIO is updated. ResolvingFileIO and the GCS/ADLS equivalents are unchanged — a catalog that wants this behavior today needs to vend io-impl: S3FileIO per-table via the REST LoadTableResponse.config() map (the specified mechanism for a catalog to select a FileIO for a table), rather than relying on ResolvingFileIO's scheme-based dispatch. Extending the other cloud FileIOs to the same short-circuit pattern is a natural follow-up.
  3. Positional deletes are not supported.
  4. SplitScanTasks are already unsupported on the remote scan-plan read path, as are multiple deletion vectors in the same deletion file. These are known limitations of the remote scan-plan endpoint and is an orthogonal fix. (Core, REST: Fix delete file references for DVs in the same Puffin file #17497)

Test plan

  • Pass the CIs
  • Optionally, with AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, and AWS_TEST_BUCKET set: ./gradlew :iceberg-aws:integrationTest --tests org.apache.iceberg.aws.s3.TestS3FileIOLivePresignedUrls

AI Disclosure

  • Model: Claude Opus 4.8
  • Platform/Tool: Cursor
  • Human Oversight: fully reviewed
  • Prompt Summary: Implement a mixin-based HTTP(S) read path for S3FileIO so readers can fetch bytes from catalog-vended pre-signed URLs without native S3 credentials, plus unit/integration/live-AWS test coverage.

@singhpk234 singhpk234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the work @williamhyun !

Added first round of comments

Comment on lines +75 to +81
if (httpClient == null) {
synchronized (this) {
if (httpClient == null) {
this.httpClient = HttpClients.custom().useSystemProperties().build();
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow-up : we would likely want to have these configurable rather than relying on SDK default or system props ?

Comment on lines +59 to +71
private final StackTraceElement[] createStack;
private final CloseableHttpClient client;
private final String location;
private final String url;

/** Cached chunk buffer. {@code bufferFileStart} is the file offset of {@code buffer[0]}. */
private byte[] buffer;

private long bufferFileStart = -1L;
private int bufferLimit = 0;

private long next = 0;
private boolean closed = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets integrate the metrics too, we need a counter to track bytes read ... like done in S3InputStream ?

check this : https://github.com/apache/iceberg/pull/17236/changes

Comment on lines +41 to +43
return location != null
&& (location.regionMatches(true, 0, "https://", 0, 8)
|| location.regionMatches(true, 0, "http://", 0, 7));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if there is existing utils to extract scheme ? if yes can we use that ?

@williamhyun

Copy link
Copy Markdown
Member Author

Thank you @singhpk234 for the comments, I have pushed with the most recent changes, please feel free to review again!

@williamhyun williamhyun changed the title AWS, Core: Read S3 files via catalog-vended HTTPS location AWS, Core: Read S3 files via catalog-vended HTTPS URLs Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants