Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.google.api.client.util.FieldInfo;
import com.google.api.core.InternalApi;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.NullMarked;
Expand All @@ -52,6 +53,33 @@
return null;
}

/**
* Retrieves the first string value of a header by case-insensitive name from a headers map.
*
* @param headers the map of header names to header values
* @param name the case-insensitive header name to look up
* @return the first string value of the header, or {@code null} if not found
*/
public static @Nullable String getFirstHeader(Map<String, Object> headers, String name) {
for (Map.Entry<String, Object> entry : headers.entrySet()) {
if (name.equalsIgnoreCase(entry.getKey())) {
return extractFirstString(entry.getValue());
}
}
return null;
}

private static @Nullable String extractFirstString(@Nullable Object headerValue) {
if (headerValue == null) {
return null;
}
if (headerValue instanceof Iterable) {
Object firstElement = Iterables.getFirst((Iterable<?>) headerValue, null);

Check warning on line 77 in sdk-platform-java/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpHeadersUtils.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Annotate the parameter with @javax.annotation.Nullable in method 'getFirst' declaration, or make sure that null can not be passed as argument.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaAcWNCOQazf8tr0eWPI&open=AaAcWNCOQazf8tr0eWPI&pullRequest=14137
return firstElement != null ? firstElement.toString() : null;

Check warning on line 78 in sdk-platform-java/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpHeadersUtils.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Change this condition so that it does not always evaluate to "true"

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaAcWNCOQazf8tr0eWPH&open=AaAcWNCOQazf8tr0eWPH&pullRequest=14137
}
return headerValue.toString();
}

public static HttpHeaders setHeaders(HttpHeaders headers, Map<String, String> headersMap) {
for (Map.Entry<String, String> entry : headersMap.entrySet()) {
setHeader(headers, entry.getKey(), entry.getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
*/
package com.google.api.gax.httpjson;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import com.google.api.client.http.HttpHeaders;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -130,4 +132,75 @@ void testGetUserAgentValue() {
headersMap = ImmutableMap.of("Custom-Header", "CustomHeader", "accept", "Accept");
assertNull(HttpHeadersUtils.getUserAgentValue(headersMap));
}

@Test
void getFirstHeader_exactMatch_returnsValue() {
Map<String, Object> headers =
ImmutableMap.of("X-Goog-Upload-URL", "https://test.googleapis.com/upload");

assertThat(HttpHeadersUtils.getFirstHeader(headers, "X-Goog-Upload-URL"))
.isEqualTo("https://test.googleapis.com/upload");
}

@Test
void getFirstHeader_caseInsensitiveMatch_returnsValue() {
Map<String, Object> headers =
ImmutableMap.of("X-Goog-Upload-URL", "https://test.googleapis.com/upload");

assertThat(HttpHeadersUtils.getFirstHeader(headers, "x-goog-upload-url"))
.isEqualTo("https://test.googleapis.com/upload");
}

@Test
void getFirstHeader_iterableValue_returnsFirstElement() {
Map<String, Object> headers =
ImmutableMap.of(
"Location", ImmutableList.of("https://redirect.url", "https://secondary.url"));

assertThat(HttpHeadersUtils.getFirstHeader(headers, "location"))
.isEqualTo("https://redirect.url");
}

@Test
void getFirstHeader_nonStringValue_convertsToString() {
Map<String, Object> headers = ImmutableMap.of("Content-Length", 1024L);

assertThat(HttpHeadersUtils.getFirstHeader(headers, "content-length")).isEqualTo("1024");
}

@Test
void getFirstHeader_emptyIterable_returnsNull() {
Map<String, Object> headers = ImmutableMap.of("Empty-List-Header", ImmutableList.of());

assertThat(HttpHeadersUtils.getFirstHeader(headers, "empty-list-header")).isNull();
}

@Test
void getFirstHeader_nullFirstElementInIterable_returnsNull() {
Map<String, Object> headers =
Collections.singletonMap("Null-First-Header", Collections.singletonList(null));

assertThat(HttpHeadersUtils.getFirstHeader(headers, "null-first-header")).isNull();
}

@Test
void getFirstHeader_nullValueInMap_returnsNull() {
Map<String, Object> headers = Collections.singletonMap("Null-Value-Header", null);

assertThat(HttpHeadersUtils.getFirstHeader(headers, "null-value-header")).isNull();
}

@Test
void getFirstHeader_nullKeyInMap_returnsNull() {
Map<String, Object> headers = Collections.singletonMap(null, "some-value");

assertThat(HttpHeadersUtils.getFirstHeader(headers, "any-header")).isNull();
}

@Test
void getFirstHeader_headerNotFound_returnsNull() {
Map<String, Object> headers = ImmutableMap.of("Existing-Header", "value");

assertThat(HttpHeadersUtils.getFirstHeader(headers, "non-existent-header")).isNull();
}
}
Loading