Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: microsoft/kiota-java
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.6.0
Choose a base ref
...
head repository: microsoft/kiota-java
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.7.0
Choose a head ref
  • 4 commits
  • 11 files changed
  • 1 contributor

Commits on Aug 14, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    c0d3ec7 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    36d2a8a View commit details
  3. - fixes indent

    Signed-off-by: Vincent Biret <vibiret@microsoft.com>
    baywet committed Aug 14, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f12e357 View commit details
  4. Merge pull request #575 from microsoft/feature/header-observe

    - adds headers inspection middleware
    baywet authored Aug 14, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    1a1fc24 View commit details
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

## [0.7.0] - 2023-08-18

### Added

- Added headers inspection option and handler.

## [0.6.0] - 2023-08-08

### Changed
Original file line number Diff line number Diff line change
@@ -13,14 +13,18 @@
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;

class CaseInsensitiveMap implements Map<String, Set<String>>{
/**
* A map that is case insensitive on the keys
*/
public class CaseInsensitiveMap implements Map<String, Set<String>>{
private final HashMap<String, HashSet<String>> internalMap = new HashMap<>();

/**
* Formats the string to lower case
* @param key string to normalize to lower case
* @return The normalized string
*/
@Nonnull
protected String normalizeKey(@Nonnull final String key) {
Objects.requireNonNull(key);
return key.toLowerCase(Locale.ROOT);
Original file line number Diff line number Diff line change
@@ -6,14 +6,19 @@

import jakarta.annotation.Nonnull;

class Headers extends CaseInsensitiveMap {
/**
* A class representing the headers of a request or a response.
*/
public abstract class Headers extends CaseInsensitiveMap {
/** Default constructor */
public Headers() {
protected Headers() {
super();
}

/** Copy constructor */
public Headers(@Nonnull Headers headers) {
/** Copy constructor
* @param headers The headers to initialize with.
*/
protected Headers(@Nonnull Headers headers) {
super();
Objects.requireNonNull(headers);
putAll(headers);
5 changes: 5 additions & 0 deletions components/http/okHttp/spotBugsExcludeFilter.xml
Original file line number Diff line number Diff line change
@@ -7,9 +7,14 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu
<Bug pattern="EI_EXPOSE_REP2" />
<Or>
<Class name="com.microsoft.kiota.http.middleware.UserAgentHandler" />
<Class name="com.microsoft.kiota.http.middleware.HeadersInspectionHandler" />
<Class name="com.microsoft.kiota.http.OkHttpRequestAdapter" />
</Or>
</Match>
<Match>
<Bug pattern="EI_EXPOSE_REP" />
<Class name="com.microsoft.kiota.http.middleware.options.HeadersInspectionOption" />
</Match>
<Match>
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
<Class name="com.microsoft.kiota.http.OkHttpRequestAdapter" />
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
import com.microsoft.kiota.http.middleware.RedirectHandler;
import com.microsoft.kiota.http.middleware.RetryHandler;
import com.microsoft.kiota.http.middleware.UserAgentHandler;
import com.microsoft.kiota.http.middleware.HeadersInspectionHandler;
import com.microsoft.kiota.http.middleware.ParametersNameDecodingHandler;

import okhttp3.Interceptor;
@@ -50,7 +51,8 @@ public static Interceptor[] createDefaultInterceptors() {
new RedirectHandler(),
new RetryHandler(),
new ParametersNameDecodingHandler(),
new UserAgentHandler()
new UserAgentHandler(),
new HeadersInspectionHandler()
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.microsoft.kiota.http.middleware;

import jakarta.annotation.Nonnull;
import kotlin.Pair;

import java.io.IOException;
import java.util.Objects;
import java.util.Set;

import com.microsoft.kiota.http.middleware.options.HeadersInspectionOption;
import com.microsoft.kiota.http.middleware.options.RetryHandlerOption;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

/**
* The middleware responsible for inspecting the request and response headers
*/
public class HeadersInspectionHandler implements Interceptor {
/**
* Create a new instance of the HeadersInspectionHandler class with the default options
*/
public HeadersInspectionHandler() {
this(new HeadersInspectionOption());
}
/**
* Create a new instance of the HeadersInspectionHandler class with the provided options
* @param options The options to use for the handler
*/
public HeadersInspectionHandler(@Nonnull final HeadersInspectionOption options) {
this.options = Objects.requireNonNull(options);
}
private final HeadersInspectionOption options;

/** {@inheritDoc} */
@Nonnull
@Override
@SuppressWarnings("UnknownNullness")
public Response intercept(final Chain chain) throws IOException {
Objects.requireNonNull(chain, "parameter chain cannot be null");
Request request = chain.request();
HeadersInspectionOption inspectionOption = request.tag(HeadersInspectionOption.class);
if(inspectionOption == null) { inspectionOption = options; }
final Span span = ObservabilityHelper.getSpanForRequest(request, "HeadersInspectionHandler_Intercept");
Scope scope = null;
if (span != null) {
scope = span.makeCurrent();
span.setAttribute("com.microsoft.kiota.handler.headersInspection.enable", true);
}
try {
if (span != null) {
request = request.newBuilder().tag(Span.class, span).build();
}
if (inspectionOption.getInspectRequestHeaders()) {
for(final Pair<? extends String, ? extends String> header : request.headers()) {
inspectionOption.getRequestHeaders().put(header.getFirst(), Set.of(header.getSecond()));
}
}
final Response response = chain.proceed(request);
if (inspectionOption.getInspectResponseHeaders()) {
for(final Pair<? extends String, ? extends String> header : response.headers()) {
inspectionOption.getResponseHeaders().put(header.getFirst(), Set.of(header.getSecond()));
}
}
return response;
} finally {
if (scope != null) {
scope.close();
}
if (span != null) {
span.end();
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.microsoft.kiota.http.middleware.options;

import jakarta.annotation.Nonnull;

import com.microsoft.kiota.RequestHeaders;
import com.microsoft.kiota.RequestOption;
import com.microsoft.kiota.ResponseHeaders;

/**
* The options to be passed to the headers inspection middleware.
*/
public class HeadersInspectionOption implements RequestOption {
private boolean inspectRequestHeaders;
/**
* Gets whether to inspect request headers
* @return Whether to inspect request headers
*/
public boolean getInspectRequestHeaders() {
return inspectRequestHeaders;
}
/**
* Sets whether to inspect request headers
* @param inspectRequestHeaders Whether to inspect request headers
*/
public void setInspectRequestHeaders(boolean inspectRequestHeaders) {
this.inspectRequestHeaders = inspectRequestHeaders;
}

private boolean inspectResponseHeaders;
/**
* Gets whether to inspect response headers
* @return Whether to inspect response headers
*/
public boolean getInspectResponseHeaders() {
return inspectResponseHeaders;
}
/**
* Sets whether to inspect response headers
* @param inspectResponseHeaders Whether to inspect response headers
*/
public void setInspectResponseHeaders(boolean inspectResponseHeaders) {
this.inspectResponseHeaders = inspectResponseHeaders;
}

private final RequestHeaders requestHeaders = new RequestHeaders();
private final ResponseHeaders responseHeaders = new ResponseHeaders();
/**
* Create default instance of headers inspection options, with default values of inspectRequestHeaders and inspectResponseHeaders.
*/
public HeadersInspectionOption() {
this(false, false);
}
/**
* Create an instance with provided values
* @param shouldInspectResponseHeaders Whether to inspect response headers
* @param shouldInspectRequestHeaders Whether to inspect request headers
*/
public HeadersInspectionOption(final boolean shouldInspectRequestHeaders, final boolean shouldInspectResponseHeaders) {
this.inspectResponseHeaders = shouldInspectResponseHeaders;
this.inspectRequestHeaders = shouldInspectRequestHeaders;
}
/**
* Get the request headers
* @return The request headers
*/
@Nonnull
public RequestHeaders getRequestHeaders() {
return this.requestHeaders;
}
/**
* Get the response headers
* @return The response headers
*/
@Nonnull
public ResponseHeaders getResponseHeaders() {
return this.responseHeaders;
}

/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
@Nonnull
public <T extends RequestOption> Class<T> getType() {
return (Class<T>) HeadersInspectionOption.class;
}

}
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ public UserAgentHandlerOption() { }
@Nonnull
private String productName = "kiota-java";
@Nonnull
private String productVersion = "0.6.0";
private String productVersion = "0.7.0";
/**
* Gets the product name to be used in the user agent header
* @return the product name
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.microsoft.kiota.http;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;

import org.junit.jupiter.api.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import com.microsoft.kiota.http.middleware.HeadersInspectionHandler;
import com.microsoft.kiota.http.middleware.options.HeadersInspectionOption;

import okhttp3.Headers;
import okhttp3.Interceptor.Chain;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

class HeadersInspectionHandlerTest {
private final Chain mockChain;
private final Response mockResponse;
public HeadersInspectionHandlerTest() throws IOException {
mockResponse = mock(Response.class);
when(mockResponse.code()).thenReturn(200);
when(mockResponse.message()).thenReturn("OK");
when(mockResponse.body()).thenReturn(mock(ResponseBody.class));
when(mockResponse.headers()).thenReturn(new Headers.Builder().add("test", "test").build());
mockChain = mock(Chain.class);
when(mockChain.proceed(any(Request.class))).thenAnswer(new Answer<Response>() {
public Response answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Request request = (Request) args[0];
when(mockResponse.request()).thenReturn(request);
return mockResponse;
}
});
}
@Test
void instantiatesWithDefaults() {
final HeadersInspectionHandler handler = new HeadersInspectionHandler();
assertNotNull(handler);
}
@Test
void getsRequestHeaders() throws IOException {
final HeadersInspectionOption option = new HeadersInspectionOption(true, false);
final HeadersInspectionHandler handler = new HeadersInspectionHandler(option);
final Request request = new Request.Builder().url("http://localhost").addHeader("test", "test").build();
when(mockChain.request()).thenReturn(request);
handler.intercept(mockChain);
assertNotNull(option.getRequestHeaders());
assertNotNull(option.getResponseHeaders());
assertEquals(1, option.getRequestHeaders().size());
assertEquals(0, option.getResponseHeaders().size());
assertEquals("test", option.getRequestHeaders().get("test").toArray()[0]);
}
@Test
void getsResponseHeaders() throws IOException {
final HeadersInspectionOption option = new HeadersInspectionOption(false, true);
final HeadersInspectionHandler handler = new HeadersInspectionHandler(option);
final Request request = new Request.Builder().url("http://localhost").addHeader("test", "test").build();
when(mockChain.request()).thenReturn(request);
handler.intercept(mockChain);
assertNotNull(option.getRequestHeaders());
assertNotNull(option.getResponseHeaders());
assertEquals(0, option.getRequestHeaders().size());
assertEquals(1, option.getResponseHeaders().size());
assertEquals("test", option.getResponseHeaders().get("test").toArray()[0]);
}
}
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
import com.microsoft.kiota.http.middleware.UserAgentHandler;
import com.microsoft.kiota.http.middleware.options.UserAgentHandlerOption;

public class UserAgentHandlerTest {
class UserAgentHandlerTest {
private final Chain mockChain;
private final Response mockResponse;
public UserAgentHandlerTest() throws IOException {
@@ -39,10 +39,10 @@ public Object answer(InvocationOnMock invocation) {
when(mockResponse.request()).thenReturn(request);
return mockResponse;
}
});
});
}
@Test
public void addsTheProduct() throws IOException {
void addsTheProduct() throws IOException {
final UserAgentHandler handler = new UserAgentHandler();
final Request request = new Request.Builder().url("http://localhost").build();
when(mockChain.request()).thenReturn(request);
@@ -53,7 +53,7 @@ public void addsTheProduct() throws IOException {
assertEquals("kiota-java", result.header("User-Agent").split("/")[0]);
}
@Test
public void addsTheProductOnce() throws IOException {
void addsTheProductOnce() throws IOException {
final UserAgentHandler handler = new UserAgentHandler();
final Request request = new Request.Builder().url("http://localhost").build();
when(mockChain.request()).thenReturn(request);
@@ -65,7 +65,7 @@ public void addsTheProductOnce() throws IOException {
assertEquals(1, result.header("User-Agent").split("kiota-java").length - 1);
}
@Test
public void doesNotAddTheProductWhenDisabled() throws IOException {
void doesNotAddTheProductWhenDisabled() throws IOException {
final UserAgentHandler handler = new UserAgentHandler(new UserAgentHandlerOption() {{ setEnabled(false); }});
final Request request = new Request.Builder().url("http://localhost").build();
when(mockChain.request()).thenReturn(request);
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ org.gradle.caching=true

mavenGroupId = com.microsoft.kiota
mavenMajorVersion = 0
mavenMinorVersion = 6
mavenMinorVersion = 7
mavenPatchVersion = 0
mavenArtifactSuffix =