Skip to content

Commit aa77c79

Browse files
authored
Apply RequestOptions Callback Before Validation in RestProxy (Azure#25176)
Apply RequestOptions Callback Before Validation in RestProxy
1 parent d8bd19d commit aa77c79

18 files changed

+189
-139
lines changed

sdk/core/azure-core-test/src/main/java/com/azure/core/test/implementation/RestProxyTests.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.azure.core.http.policy.HttpLogOptions;
3232
import com.azure.core.http.policy.HttpLoggingPolicy;
3333
import com.azure.core.http.policy.PortPolicy;
34+
import com.azure.core.http.rest.RequestOptions;
3435
import com.azure.core.http.rest.Response;
3536
import com.azure.core.http.rest.ResponseBase;
3637
import com.azure.core.http.rest.RestProxy;
@@ -40,6 +41,7 @@
4041
import com.azure.core.test.implementation.entities.HttpBinFormDataJSON.PizzaSize;
4142
import com.azure.core.test.implementation.entities.HttpBinHeaders;
4243
import com.azure.core.test.implementation.entities.HttpBinJSON;
44+
import com.azure.core.util.BinaryData;
4345
import com.azure.core.util.FluxUtil;
4446
import org.junit.jupiter.api.Assertions;
4547
import org.junit.jupiter.api.Test;
@@ -1684,6 +1686,69 @@ public void postUrlFormEncoded() {
16841686
assertEquals("Onion", response.form().toppings().get(1));
16851687
}
16861688

1689+
@Host("http://localhost")
1690+
@ServiceInterface(name = "Service27")
1691+
interface Service27 {
1692+
@Put("put")
1693+
@ExpectedResponses({200})
1694+
HttpBinJSON put(@BodyParam(ContentType.APPLICATION_OCTET_STREAM) int putBody, RequestOptions requestOptions);
1695+
1696+
@Put("put")
1697+
@ExpectedResponses({200})
1698+
@UnexpectedResponseExceptionType(MyRestException.class)
1699+
HttpBinJSON putBodyAndContentLength(@BodyParam(ContentType.APPLICATION_OCTET_STREAM) ByteBuffer body,
1700+
@HeaderParam("Content-Length") long contentLength, RequestOptions requestOptions);
1701+
}
1702+
1703+
@Test
1704+
public void requestOptionsChangesBody() {
1705+
Service27 service = createService(Service27.class);
1706+
1707+
HttpBinJSON response = service.put(42, new RequestOptions().setBody(BinaryData.fromString("24")));
1708+
assertNotNull(response);
1709+
assertNotNull(response.data());
1710+
assertTrue(response.data() instanceof String);
1711+
assertEquals("24", response.data());
1712+
}
1713+
1714+
@Test
1715+
public void requestOptionsChangesBodyAndContentLength() {
1716+
Service27 service = createService(Service27.class);
1717+
1718+
HttpBinJSON response = service.put(42, new RequestOptions().setBody(BinaryData.fromString("4242"))
1719+
.setHeader("Content-Length", "4"));
1720+
assertNotNull(response);
1721+
assertNotNull(response.data());
1722+
assertTrue(response.data() instanceof String);
1723+
assertEquals("4242", response.data());
1724+
assertEquals("4", response.getHeaderValue("Content-Length"));
1725+
}
1726+
1727+
@Test
1728+
public void requestOptionsAddAHeader() {
1729+
Service27 service = createService(Service27.class);
1730+
1731+
HttpBinJSON response = service.put(42, new RequestOptions().addHeader("randomHeader", "randomValue"));
1732+
assertNotNull(response);
1733+
assertNotNull(response.data());
1734+
assertTrue(response.data() instanceof String);
1735+
assertEquals("42", response.data());
1736+
assertEquals("randomValue", response.getHeaderValue("randomHeader"));
1737+
}
1738+
1739+
@Test
1740+
public void requestOptionsSetsAHeader() {
1741+
Service27 service = createService(Service27.class);
1742+
1743+
HttpBinJSON response = service.put(42, new RequestOptions().addHeader("randomHeader", "randomValue")
1744+
.setHeader("randomHeader", "randomValue2"));
1745+
assertNotNull(response);
1746+
assertNotNull(response.data());
1747+
assertTrue(response.data() instanceof String);
1748+
assertEquals("42", response.data());
1749+
assertEquals("randomValue2", response.getHeaderValue("randomHeader"));
1750+
}
1751+
16871752
// Helpers
16881753
protected <T> T createService(Class<T> serviceClass) {
16891754
final HttpClient httpClient = createHttpClient();

sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RequestOptions.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package com.azure.core.http.rest;
55

66
import com.azure.core.annotation.QueryParam;
7-
import com.azure.core.http.HttpHeader;
87
import com.azure.core.http.HttpRequest;
98
import com.azure.core.util.BinaryData;
109
import com.azure.core.util.Context;
@@ -156,20 +155,30 @@ Context getContext() {
156155

157156
/**
158157
* Adds a header to the HTTP request.
158+
* <p>
159+
* If a header with the given name exists the {@code value} is added to the existing header (comma-separated),
160+
* otherwise a new header is created.
159161
*
160162
* @param header the header key
161163
* @param value the header value
162164
* @return the modified RequestOptions object
163165
*/
164166
public RequestOptions addHeader(String header, String value) {
165-
this.requestCallback = this.requestCallback.andThen(request -> {
166-
HttpHeader httpHeader = request.getHeaders().get(header);
167-
if (httpHeader == null) {
168-
request.getHeaders().set(header, value);
169-
} else {
170-
httpHeader.addValue(value);
171-
}
172-
});
167+
this.requestCallback = this.requestCallback.andThen(request -> request.getHeaders().add(header, value));
168+
return this;
169+
}
170+
171+
/**
172+
* Sets a header on the HTTP request.
173+
* <p>
174+
* If a header with the given name exists it is overridden by the new {@code value}.
175+
*
176+
* @param header the header key
177+
* @param value the header value
178+
* @return the modified RequestOptions object
179+
*/
180+
public RequestOptions setHeader(String header, String value) {
181+
this.requestCallback = this.requestCallback.andThen(request -> request.getHeaders().set(header, value));
173182
return this;
174183
}
175184

sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RestProxy.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,16 @@ public Object invoke(Object proxy, final Method method, Object[] args) {
131131
.addData("azure-eagerly-read-response", shouldEagerlyReadResponse(methodParser.getReturnType()));
132132
context = startTracingSpan(method, context);
133133

134-
if (request.getBody() != null) {
135-
request.setBody(validateLength(request));
136-
}
137-
134+
// If there is 'RequestOptions' apply its request callback operations before validating the body.
135+
// This is because the callbacks may mutate the request body.
138136
if (options != null) {
139137
options.getRequestCallback().accept(request);
140138
}
141139

140+
if (request.getBody() != null) {
141+
request.setBody(validateLength(request));
142+
}
143+
142144
final Mono<HttpResponse> asyncResponse = send(request, context);
143145

144146
Mono<HttpDecodedResponse> asyncDecodedResponse = this.decoder.decode(asyncResponse, methodParser);

sdk/webpubsub/azure-messaging-webpubsub/src/main/java/com/azure/messaging/webpubsub/WebPubSubServiceAsyncClient.java

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,8 @@ public Mono<Response<Void>> sendToAllWithResponse(
131131
if (requestOptions == null) {
132132
requestOptions = new RequestOptions();
133133
}
134-
requestOptions.addHeader("Content-Type", contentType.toString());
135-
requestOptions.addRequestCallback(httpRequest -> {
136-
if (httpRequest.getHeaders().stream()
137-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
138-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
139-
}
140-
});
134+
requestOptions.setHeader("Content-Type", contentType.toString());
135+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
141136
return this.serviceClient.sendToAllWithResponseAsync(hub, message, requestOptions);
142137
}
143138

@@ -167,8 +162,8 @@ public Mono<Response<Void>> sendToAllWithResponse(BinaryData message, RequestOpt
167162
@ServiceMethod(returns = ReturnType.SINGLE)
168163
public Mono<Void> sendToAll(String message, WebPubSubContentType contentType) {
169164
return sendToAllWithResponse(BinaryData.fromString(message),
170-
new RequestOptions().addRequestCallback(request -> request.getHeaders().set("Content-Type",
171-
contentType.toString()))).flatMap(FluxUtil::toMono);
165+
new RequestOptions().setHeader("Content-Type", contentType.toString()))
166+
.flatMap(FluxUtil::toMono);
172167
}
173168

174169
/**
@@ -223,13 +218,8 @@ public Mono<Response<Void>> sendToConnectionWithResponse(
223218
if (requestOptions == null) {
224219
requestOptions = new RequestOptions();
225220
}
226-
requestOptions.addHeader("Content-Type", contentType.toString());
227-
requestOptions.addRequestCallback(httpRequest -> {
228-
if (httpRequest.getHeaders().stream()
229-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
230-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
231-
}
232-
});
221+
requestOptions.setHeader("Content-Type", contentType.toString());
222+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
233223
return this.serviceClient.sendToConnectionWithResponseAsync(
234224
hub, connectionId, message, requestOptions);
235225
}
@@ -264,8 +254,7 @@ public Mono<Response<Void>> sendToConnectionWithResponse(
264254
public Mono<Void> sendToConnection(
265255
String connectionId, String message, WebPubSubContentType contentType) {
266256
return this.sendToConnectionWithResponse(connectionId, BinaryData.fromString(message),
267-
new RequestOptions().addRequestCallback(request -> request.getHeaders()
268-
.set("Content-Type", contentType.toString()))).flatMap(FluxUtil::toMono);
257+
new RequestOptions().setHeader("Content-Type", contentType.toString())).flatMap(FluxUtil::toMono);
269258
}
270259

271260
/**
@@ -304,13 +293,8 @@ public Mono<Response<Void>> sendToGroupWithResponse(
304293
if (requestOptions == null) {
305294
requestOptions = new RequestOptions();
306295
}
307-
requestOptions.addHeader("Content-Type", contentType.toString());
308-
requestOptions.addRequestCallback(httpRequest -> {
309-
if (httpRequest.getHeaders().stream()
310-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
311-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
312-
}
313-
});
296+
requestOptions.setHeader("Content-Type", contentType.toString());
297+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
314298
return this.serviceClient.sendToGroupWithResponseAsync(
315299
hub, group, message, requestOptions);
316300
}
@@ -344,7 +328,7 @@ public Mono<Response<Void>> sendToGroupWithResponse(
344328
@ServiceMethod(returns = ReturnType.SINGLE)
345329
public Mono<Void> sendToGroup(String group, String message, WebPubSubContentType contentType) {
346330
return sendToGroupWithResponse(group, BinaryData.fromString(message), new RequestOptions()
347-
.addRequestCallback(request -> request.getHeaders().set("Content-Type", contentType.toString())))
331+
.setHeader("Content-Type", contentType.toString()))
348332
.flatMap(FluxUtil::toMono);
349333
}
350334

@@ -416,13 +400,8 @@ public Mono<Response<Void>> sendToUserWithResponse(
416400
if (requestOptions == null) {
417401
requestOptions = new RequestOptions();
418402
}
419-
requestOptions.addHeader("Content-Type", contentType.toString());
420-
requestOptions.addRequestCallback(httpRequest -> {
421-
if (httpRequest.getHeaders().stream()
422-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
423-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
424-
}
425-
});
403+
requestOptions.setHeader("Content-Type", contentType.toString());
404+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
426405
return this.serviceClient.sendToUserWithResponseAsync(
427406
hub, userId, message, requestOptions);
428407
}
@@ -456,7 +435,7 @@ public Mono<Response<Void>> sendToUserWithResponse(
456435
@ServiceMethod(returns = ReturnType.SINGLE)
457436
public Mono<Void> sendToUser(String userId, String message, WebPubSubContentType contentType) {
458437
return sendToUserWithResponse(userId, BinaryData.fromString(message), new RequestOptions()
459-
.addRequestCallback(request -> request.getHeaders().set("Content-Type", contentType.toString())))
438+
.setHeader("Content-Type", contentType.toString()))
460439
.flatMap(FluxUtil::toMono);
461440
}
462441

sdk/webpubsub/azure-messaging-webpubsub/src/main/java/com/azure/messaging/webpubsub/WebPubSubServiceClient.java

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,8 @@ public Response<Void> sendToAllWithResponse(
129129
if (requestOptions == null) {
130130
requestOptions = new RequestOptions();
131131
}
132-
requestOptions.addHeader("Content-Type", contentType.toString());
133-
requestOptions.addRequestCallback(httpRequest -> {
134-
if (httpRequest.getHeaders().stream()
135-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
136-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
137-
}
138-
});
132+
requestOptions.setHeader("Content-Type", contentType.toString());
133+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
139134
return this.serviceClient.sendToAllWithResponse(
140135
hub, message, requestOptions);
141136
}
@@ -151,8 +146,7 @@ public Response<Void> sendToAllWithResponse(
151146
@ServiceMethod(returns = ReturnType.SINGLE)
152147
public void sendToAll(String message, WebPubSubContentType contentType) {
153148
sendToAllWithResponse(BinaryData.fromString(message),
154-
new RequestOptions().addRequestCallback(request -> request.getHeaders().set("Content-Type",
155-
contentType.toString())));
149+
new RequestOptions().setHeader("Content-Type", contentType.toString()));
156150
}
157151

158152
/**
@@ -222,13 +216,8 @@ public Response<Void> sendToConnectionWithResponse(
222216
if (requestOptions == null) {
223217
requestOptions = new RequestOptions();
224218
}
225-
requestOptions.addHeader("Content-Type", contentType.toString());
226-
requestOptions.addRequestCallback(httpRequest -> {
227-
if (httpRequest.getHeaders().stream()
228-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
229-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
230-
}
231-
});
219+
requestOptions.setHeader("Content-Type", contentType.toString());
220+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
232221
return this.serviceClient.sendToConnectionWithResponse(
233222
hub, connectionId, message, requestOptions);
234223
}
@@ -246,8 +235,7 @@ public Response<Void> sendToConnectionWithResponse(
246235
public void sendToConnection(
247236
String connectionId, String message, WebPubSubContentType contentType) {
248237
this.sendToConnectionWithResponse(connectionId, BinaryData.fromString(message),
249-
new RequestOptions().addRequestCallback(request -> request.getHeaders()
250-
.set("Content-Type", contentType.toString())));
238+
new RequestOptions().setHeader("Content-Type", contentType.toString()));
251239
}
252240

253241
/**
@@ -303,13 +291,8 @@ public Response<Void> sendToGroupWithResponse(
303291
if (requestOptions == null) {
304292
requestOptions = new RequestOptions();
305293
}
306-
requestOptions.addHeader("Content-Type", contentType.toString());
307-
requestOptions.addRequestCallback(httpRequest -> {
308-
if (httpRequest.getHeaders().stream()
309-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
310-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
311-
}
312-
});
294+
requestOptions.setHeader("Content-Type", contentType.toString());
295+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
313296
return this.serviceClient.sendToGroupWithResponse(
314297
hub, group, message, requestOptions);
315298
}
@@ -326,7 +309,7 @@ public Response<Void> sendToGroupWithResponse(
326309
@ServiceMethod(returns = ReturnType.SINGLE)
327310
public void sendToGroup(String group, String message, WebPubSubContentType contentType) {
328311
sendToGroupWithResponse(group, BinaryData.fromString(message), new RequestOptions()
329-
.addRequestCallback(request -> request.getHeaders().set("Content-Type", contentType.toString())));
312+
.setHeader("Content-Type", contentType.toString()));
330313
}
331314

332315
/**
@@ -415,13 +398,8 @@ public Response<Void> sendToUserWithResponse(
415398
if (requestOptions == null) {
416399
requestOptions = new RequestOptions();
417400
}
418-
requestOptions.addHeader("Content-Type", contentType.toString());
419-
requestOptions.addRequestCallback(httpRequest -> {
420-
if (httpRequest.getHeaders().stream()
421-
.noneMatch(header -> header.getName().equalsIgnoreCase("Content-Length"))) {
422-
httpRequest.setHeader("Content-Length", String.valueOf(contentLength));
423-
}
424-
});
401+
requestOptions.setHeader("Content-Type", contentType.toString());
402+
requestOptions.setHeader("Content-Length", String.valueOf(contentLength));
425403
return this.serviceClient.sendToUserWithResponse(
426404
hub, userId, message, requestOptions);
427405
}
@@ -438,7 +416,7 @@ public Response<Void> sendToUserWithResponse(
438416
@ServiceMethod(returns = ReturnType.SINGLE)
439417
public void sendToUser(String userId, String message, WebPubSubContentType contentType) {
440418
sendToUserWithResponse(userId, BinaryData.fromString(message), new RequestOptions()
441-
.addRequestCallback(request -> request.getHeaders().set("Content-Type", contentType.toString())));
419+
.setHeader("Content-Type", contentType.toString()));
442420
}
443421

444422
/**

sdk/webpubsub/azure-messaging-webpubsub/src/test/java/com/azure/messaging/webpubsub/WebPubSubServiceClientTests.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.junit.jupiter.api.BeforeEach;
2727
import org.junit.jupiter.api.Test;
2828

29+
import java.io.ByteArrayInputStream;
2930
import java.nio.charset.StandardCharsets;
3031
import java.text.ParseException;
3132
import java.util.EnumSet;
@@ -110,12 +111,12 @@ public void testSendToUserString() {
110111
null),
111112
202);
112113

113-
// ByteArrayInputStream messageStream = new ByteArrayInputStream(message.toBytes());
114-
// assertResponse(client.sendToUserWithResponse("test_user",
115-
// BinaryData.fromStream(messageStream),
116-
// WebPubSubContentType.APPLICATION_OCTET_STREAM, message.getLength(),
117-
// null),
118-
// 202);
114+
ByteArrayInputStream messageStream = new ByteArrayInputStream(message.toBytes());
115+
assertResponse(client.sendToUserWithResponse("test_user",
116+
BinaryData.fromStream(messageStream),
117+
WebPubSubContentType.APPLICATION_OCTET_STREAM, message.getLength(),
118+
null),
119+
202);
119120
}
120121

121122
@Test

0 commit comments

Comments
 (0)