Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
],
"java.configuration.updateBuildConfiguration": "interactive",
"java.compile.nullAnalysis.mode": "automatic"
}
}
28 changes: 19 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

### Changed

## [1.1.5]

### Changed

- Fixed exception thrown when setting content length on stream request bodies.

## [1.1.4] - 2024-04-04

### Added
Expand All @@ -33,7 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Fixed a bug where not providing scopes to `AzureIdentityAccessTokenProvider` failed with `UnsupportedOperationException` when attempting to fetch the token. [microsoftgraph/msgraph-sdk-java#1882](https://github.com/microsoftgraph/msgraph-sdk-java/issues/1882)
- Fixed a bug where not providing scopes to `AzureIdentityAccessTokenProvider` failed with `UnsupportedOperationException` when attempting to fetch the token. [microsoftgraph/msgraph-sdk-java#1882](https://github.com/microsoftgraph/msgraph-sdk-java/issues/1882)

## [1.1.0] - 2024-02-14

Expand All @@ -43,13 +53,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [1.0.6] - 2023-03-04

### Changed
### Changed

- Fixed a regression with the content length request header from 1.0.5.

## [1.0.5] - 2023-02-28

### Changed
### Changed

- Added contentLength property to RequestInformation to facilitate in setting the content length of the Okhttp3 RequestBody object within the OkhttpRequestAdapter.

Expand Down Expand Up @@ -210,7 +220,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Add PeriodAndDuration constructor to create new object from a PeriodAndDuration object.
- Add PeriodAndDuration constructor to create new object from a PeriodAndDuration object.

## [0.7.0] - 2023-08-18

Expand All @@ -222,7 +232,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Javax annotations replaced in favor of Jakarta annotations.
- Javax annotations replaced in favor of Jakarta annotations.

## [0.5.0] - 2023-07-26

Expand Down Expand Up @@ -269,8 +279,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Adds a NativeResponseHandler to abstractions.
- Adds setResponseHandler method to RequestInformation class in abstractions.
- Adds a NativeResponseHandler to abstractions.
- Adds setResponseHandler method to RequestInformation class in abstractions.

## [0.4.1] - 2023-03-29

Expand Down Expand Up @@ -373,11 +383,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added ResponseHandlerOption class.
- Added ResponseHandlerOption class.

### Changed

- Removed responseHandler parameter from RequestAdapter sendAsync methods.
- Removed responseHandler parameter from RequestAdapter sendAsync methods.
- Compatibility for Android level 26.

## [0.0.5] - 2022-09-15
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDate;
Expand Down Expand Up @@ -846,7 +845,7 @@ private void setBaseUrlForRequestInformation(@Nonnull final RequestInformation r
try (final Scope scope = span.makeCurrent()) {
this.authProvider.authenticateRequest(requestInfo, null);
return (T) getRequestFromRequestInformation(requestInfo, span, span);
} catch (URISyntaxException | MalformedURLException ex) {
} catch (URISyntaxException | IOException ex) {
span.recordException(ex);
throw new RuntimeException(ex);
} finally {
Expand All @@ -862,13 +861,13 @@ private void setBaseUrlForRequestInformation(@Nonnull final RequestInformation r
* @param spanForAttributes the span for the attributes.
* @return the created request instance.
* @throws URISyntaxException if the URI is invalid.
* @throws MalformedURLException if the URL is invalid.
* @throws IOException if the URL is invalid.
*/
protected @Nonnull Request getRequestFromRequestInformation(
@Nonnull final RequestInformation requestInfo,
@Nonnull final Span parentSpan,
@Nonnull final Span spanForAttributes)
throws URISyntaxException, MalformedURLException {
throws URISyntaxException, IOException {
final Span span =
GlobalOpenTelemetry.getTracer(obsOptions.getTracerInstrumentationName())
.spanBuilder("getRequestFromRequestInformation")
Expand Down Expand Up @@ -907,30 +906,19 @@ public MediaType contentType() {

@Override
public long contentLength() throws IOException {
long length;
final Set<String> contentLength =
requestInfo.headers.getOrDefault(
contentLengthHeaderKey, new HashSet<>());
if (contentLength.isEmpty()
&& requestInfo.content
instanceof ByteArrayInputStream) {
if (!contentLength.isEmpty()) {
return Long.parseLong(
contentLength.toArray(new String[] {})[0]);
}
if (requestInfo.content instanceof ByteArrayInputStream) {
final ByteArrayInputStream contentStream =
(ByteArrayInputStream) requestInfo.content;
length = contentStream.available();
} else {
length =
Long.parseLong(
contentLength.toArray(new String[] {})[0]);
}
if (length <= 0) {
length = super.contentLength();
}
if (length > 0) {
spanForAttributes.setAttribute(
HttpIncubatingAttributes.HTTP_REQUEST_BODY_SIZE,
length);
return contentStream.available();
}
return length;
return super.contentLength();
}

@Override
Expand Down Expand Up @@ -967,7 +955,18 @@ public void writeTo(@Nonnull BufferedSink sink) throws IOException {
requestBuilder.tag(obsOptions.getType(), obsOptions);
}
requestBuilder.tag(Span.class, parentSpan);
return requestBuilder.build();
final Request request = requestBuilder.build();
if (request != null) {
RequestBody requestBody = request.body();
if (requestBody != null) {
long contentLength = requestBody.contentLength();
if (contentLength >= 0) {
spanForAttributes.setAttribute(
HttpIncubatingAttributes.HTTP_REQUEST_BODY_SIZE, contentLength);
}
}
}
return request;
} finally {
span.end();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,21 @@ void getRequestFromRequestInformationHasCorrectContentLength_JsonPayload() throw
new ByteArrayInputStream(
"{\"name\":\"value\",\"array\":[\"1\",\"2\",\"3\"]}"
.getBytes(StandardCharsets.UTF_8));
requestInformation.setStreamContent(content, "application/octet-stream");
requestInformation.setStreamContent(content, "application/json");
requestInformation.httpMethod = HttpMethod.PUT;
requestInformation.headers.tryAdd("Content-Length", String.valueOf(content.available()));
final var contentLength = content.available();
requestInformation.headers.tryAdd("Content-Length", String.valueOf(contentLength));

final var adapter = new OkHttpRequestAdapter(authenticationProviderMock);
final var request =
adapter.getRequestFromRequestInformation(
requestInformation, mock(Span.class), mock(Span.class));

assertEquals(
String.valueOf(requestInformation.content.available()),
request.headers().get("Content-Length"));
assertEquals("application/octet-stream", request.headers().get("Content-Type"));
assertEquals(String.valueOf(contentLength), request.headers().get("Content-Length"));
assertEquals("application/json", request.headers().get("Content-Type"));
assertNotNull(request.body());
assertEquals(request.body().contentLength(), requestInformation.content.available());
assertEquals(request.body().contentType(), MediaType.parse("application/octet-stream"));
assertEquals(request.body().contentLength(), contentLength);
assertEquals(request.body().contentType(), MediaType.parse("application/json"));
}

@Test
Expand All @@ -327,7 +326,8 @@ void getRequestFromRequestInformationIncludesContentLength_FilePayload() throws

requestInformation.setUri(new URI("https://localhost"));
requestInformation.httpMethod = HttpMethod.PUT;
requestInformation.headers.add("Content-Length", String.valueOf(testFile.length()));
final var contentLength = testFile.length();
requestInformation.headers.add("Content-Length", String.valueOf(contentLength));
try (FileInputStream content = new FileInputStream(testFile)) {
requestInformation.setStreamContent(content, "application/octet-stream");

Expand All @@ -336,16 +336,82 @@ void getRequestFromRequestInformationIncludesContentLength_FilePayload() throws
adapter.getRequestFromRequestInformation(
requestInformation, mock(Span.class), mock(Span.class));

assertEquals(
String.valueOf(requestInformation.content.available()),
request.headers().get("Content-Length"));
assertEquals(String.valueOf(contentLength), request.headers().get("Content-Length"));
assertEquals("application/octet-stream", request.headers().get("Content-Type"));
assertNotNull(request.body());
assertEquals(request.body().contentLength(), requestInformation.content.available());
assertEquals(request.body().contentLength(), contentLength);
assertEquals(request.body().contentType(), MediaType.parse("application/octet-stream"));
}
}

@Test
void getRequestFromRequestInformationWithoutContentLengthOverrideForStreamBody()
throws Exception {
final var authenticationProviderMock = mock(AuthenticationProvider.class);
final var testFile = new File("./src/test/resources/helloWorld.txt");
final var requestInformation = new RequestInformation();

requestInformation.setUri(new URI("https://localhost"));
requestInformation.httpMethod = HttpMethod.PUT;
try (FileInputStream content = new FileInputStream(testFile)) {
requestInformation.setStreamContent(content, "application/octet-stream");

final var adapter = new OkHttpRequestAdapter(authenticationProviderMock);
final var request =
adapter.getRequestFromRequestInformation(
requestInformation, mock(Span.class), mock(Span.class));

assertEquals("application/octet-stream", request.headers().get("Content-Type"));
assertNotNull(request.body());
assertEquals(-1L, request.body().contentLength());
assertEquals(request.body().contentType(), MediaType.parse("application/octet-stream"));
}
}

@Test
void getRequestFromRequestInformationWithoutContentLengthOverrideForJsonPayload()
throws Exception {
final var authenticationProviderMock = mock(AuthenticationProvider.class);
final var requestInformation = new RequestInformation();
requestInformation.setUri(new URI("https://localhost"));
ByteArrayInputStream content =
new ByteArrayInputStream(
"{\"name\":\"value\",\"array\":[\"1\",\"2\",\"3\"]}"
.getBytes(StandardCharsets.UTF_8));
requestInformation.setStreamContent(content, "application/json");
requestInformation.httpMethod = HttpMethod.PUT;
final var contentLength = content.available();

final var adapter = new OkHttpRequestAdapter(authenticationProviderMock);
final var request =
adapter.getRequestFromRequestInformation(
requestInformation, mock(Span.class), mock(Span.class));

assertEquals("application/json", request.headers().get("Content-Type"));
assertNotNull(request.body());
assertEquals(contentLength, request.body().contentLength());
assertEquals(MediaType.parse("application/json"), request.body().contentType());
}

@Test
void getRequestFromRequestInformationWithoutContentLengthOverrideWithEmptyPayload()
throws Exception {
final var authenticationProviderMock = mock(AuthenticationProvider.class);
final var requestInformation = new RequestInformation();
requestInformation.setUri(new URI("https://localhost"));
ByteArrayInputStream content = new ByteArrayInputStream(new byte[0]);
requestInformation.httpMethod = HttpMethod.PUT;
requestInformation.content = content;

final var adapter = new OkHttpRequestAdapter(authenticationProviderMock);
final var request =
adapter.getRequestFromRequestInformation(
requestInformation, mock(Span.class), mock(Span.class));

assertNull(request.headers().get("Content-Type"));
assertEquals(0, request.body().contentLength());
}

public static OkHttpClient getMockClient(final Response response) throws IOException {
final OkHttpClient mockClient = mock(OkHttpClient.class);
final Call remoteCall = mock(Call.class);
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ org.gradle.caching=true
mavenGroupId = com.microsoft.kiota
mavenMajorVersion = 1
mavenMinorVersion = 1
mavenPatchVersion = 4
mavenArtifactSuffix =
mavenPatchVersion = 5
mavenArtifactSuffix =

#These values are used to run functional tests
#If you wish to run the functional tests, edit the gradle.properties
Expand Down