Skip to content

Commit

Permalink
Passthrough HTTP headers to remote downloader service
Browse files Browse the repository at this point in the history
Related to bazelbuild#17829 and bazelbuild@2697e0c

I don't love this design but according to the Remote Asset API spec, this is an intended use of qualifiers: https://docs.google.com/document/d/10ari9WtTTSv9bqB_UU-oe2gBtaAA7HyQgkpP-RFP80c/edit#heading=h.sixrlhdnkfoa.

cc @Wyverald @jmillikin

Closes bazelbuild#21490.

PiperOrigin-RevId: 610688317
Change-Id: I272f63a6bc4ea432503003ee907ca012f6d641cf
  • Loading branch information
sushain97 authored and bazel-io committed Feb 27, 2024
1 parent e57b6cc commit 6ac725c
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
Expand Up @@ -77,6 +77,11 @@ public class GrpcRemoteDownloader implements AutoCloseable, Downloader {
private static final String QUALIFIER_CHECKSUM_SRI = "checksum.sri";
private static final String QUALIFIER_CANONICAL_ID = "bazel.canonical_id";

// The `:` character is not permitted in an HTTP header name. So, we use it to
// delimit the qualifier prefix which denotes an HTTP header qualifer from the
// header name itself.
private static final String QUALIFIER_HTTP_HEADER_PREFIX = "http_header:";

public GrpcRemoteDownloader(
String buildRequestId,
String commandId,
Expand Down Expand Up @@ -125,7 +130,7 @@ public void download(
RemoteActionExecutionContext.create(metadata);

final FetchBlobRequest request =
newFetchBlobRequest(options.remoteInstanceName, urls, checksum, canonicalId);
newFetchBlobRequest(options.remoteInstanceName, urls, checksum, canonicalId, headers);
try {
FetchBlobResponse response =
retrier.execute(
Expand Down Expand Up @@ -169,24 +174,40 @@ public void download(

@VisibleForTesting
static FetchBlobRequest newFetchBlobRequest(
String instanceName, List<URL> urls, Optional<Checksum> checksum, String canonicalId) {
String instanceName,
List<URL> urls,
Optional<Checksum> checksum,
String canonicalId,
Map<String, List<String>> headers) {
FetchBlobRequest.Builder requestBuilder =
FetchBlobRequest.newBuilder().setInstanceName(instanceName);
for (URL url : urls) {
requestBuilder.addUris(url.toString());
}

if (checksum.isPresent()) {
requestBuilder.addQualifiers(
Qualifier.newBuilder()
.setName(QUALIFIER_CHECKSUM_SRI)
.setValue(checksum.get().toSubresourceIntegrity())
.build());
}

if (!Strings.isNullOrEmpty(canonicalId)) {
requestBuilder.addQualifiers(
Qualifier.newBuilder().setName(QUALIFIER_CANONICAL_ID).setValue(canonicalId).build());
}

for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
// https://www.rfc-editor.org/rfc/rfc9110.html#name-field-order permits
// merging the field-values with a comma.
requestBuilder.addQualifiers(
Qualifier.newBuilder()
.setName(QUALIFIER_HTTP_HEADER_PREFIX + entry.getKey())
.setValue(String.join(",", entry.getValue()))
.build());
}

return requestBuilder.build();
}

Expand Down
Expand Up @@ -351,7 +351,10 @@ public void testFetchBlobRequest() throws Exception {
Optional.<Checksum>of(
Checksum.fromSubresourceIntegrity(
"sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")),
"canonical ID");
"canonical ID",
ImmutableMap.of(
"Authorization", ImmutableList.of("Basic Zm9vOmJhcg=="),
"X-Custom-Token", ImmutableList.of("foo", "bar")));

assertThat(request)
.isEqualTo(
Expand All @@ -366,6 +369,14 @@ public void testFetchBlobRequest() throws Exception {
.setValue("sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="))
.addQualifiers(
Qualifier.newBuilder().setName("bazel.canonical_id").setValue("canonical ID"))
.addQualifiers(
Qualifier.newBuilder()
.setName("http_header:Authorization")
.setValue("Basic Zm9vOmJhcg=="))
.addQualifiers(
Qualifier.newBuilder()
.setName("http_header:X-Custom-Token")
.setValue("foo,bar"))
.build());
}
}

0 comments on commit 6ac725c

Please sign in to comment.