-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #575 from microsoft/feature/header-observe
- adds headers inspection middleware
- Loading branch information
Showing
11 changed files
with
275 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
...tp/okHttp/src/main/java/com/microsoft/kiota/http/middleware/HeadersInspectionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} | ||
} | ||
|
||
} |
87 changes: 87 additions & 0 deletions
87
...tp/src/main/java/com/microsoft/kiota/http/middleware/options/HeadersInspectionOption.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
...ents/http/okHttp/src/test/java/com/microsoft/kiota/http/HeadersInspectionHandlerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters