Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new async client based on Reactor Netty #123

Merged
merged 38 commits into from
May 15, 2018
Merged
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
fe4dc9a
Kick off Reactor Netty based client
acogoluegnes Apr 24, 2018
f60bbbe
Clean code of ReactorNettyClient for re-use
acogoluegnes Apr 24, 2018
904f3a3
Add roadmap items to ReactorNettyClient
acogoluegnes Apr 25, 2018
572c756
Don't rely on UriComponentsBuilder in ReactorNettyClient
acogoluegnes Apr 27, 2018
931dd01
Use Mono<String> for Authorization header
acogoluegnes Apr 30, 2018
885a409
Add URI path encoding and HTTP response wrapper
acogoluegnes May 2, 2018
5b880c8
Implement several HTTP endpoints
acogoluegnes May 2, 2018
35a3b29
Bump dependencies on 1.3.x
acogoluegnes May 2, 2018
2c685c7
Merge branch '1.3.x-stable'
acogoluegnes May 2, 2018
4706c0c
Bump Reactor release train to Bismuth-SR8
acogoluegnes May 2, 2018
2074451
Fix compilation issue
acogoluegnes May 2, 2018
9fa8644
Implement more endpoints in Reactor Netty client
acogoluegnes May 3, 2018
8092e34
Add options to make Reactor Netty client configurable
acogoluegnes May 3, 2018
1ed4fe0
Add missing tests for Reactor Netty client
acogoluegnes May 3, 2018
b3695fa
Add Javadoc to Reactor Netty client
acogoluegnes May 3, 2018
79046be
Propagate JSON exception
acogoluegnes May 3, 2018
89100f0
Bump Spring version to 4.3.17
acogoluegnes May 14, 2018
5b28558
Merge branch '1.3.x-stable'
acogoluegnes May 14, 2018
a0cd820
Bump Spring to 5.0.6 and Reactor to Bismuth-SR9
acogoluegnes May 14, 2018
ef54e3e
[artifactory-release] Release version 1.3.2.RELEASE
spring-builds May 14, 2018
cd5a4cd
[artifactory-release] Next development version
spring-builds May 14, 2018
b4db01e
[artifactory-release] Release version 2.0.2.RELEASE
spring-builds May 14, 2018
8405d17
[artifactory-release] Next development version
spring-builds May 14, 2018
4ba9632
Merge branch '1.3.x-stable'
acogoluegnes May 14, 2018
120b00b
Use 2.0.2.RELEASE in readme
acogoluegnes May 14, 2018
fb5558a
Kick off Reactor Netty based client
acogoluegnes Apr 24, 2018
52f4a49
Clean code of ReactorNettyClient for re-use
acogoluegnes Apr 24, 2018
95bea10
Add roadmap items to ReactorNettyClient
acogoluegnes Apr 25, 2018
cd31689
Don't rely on UriComponentsBuilder in ReactorNettyClient
acogoluegnes Apr 27, 2018
99e6379
Use Mono<String> for Authorization header
acogoluegnes Apr 30, 2018
411b91c
Add URI path encoding and HTTP response wrapper
acogoluegnes May 2, 2018
49ac638
Implement several HTTP endpoints
acogoluegnes May 2, 2018
265925f
Implement more endpoints in Reactor Netty client
acogoluegnes May 3, 2018
a1031ef
Add options to make Reactor Netty client configurable
acogoluegnes May 3, 2018
f31b4f2
Add missing tests for Reactor Netty client
acogoluegnes May 3, 2018
0c1c63b
Add Javadoc to Reactor Netty client
acogoluegnes May 3, 2018
304e5b1
Propagate JSON exception
acogoluegnes May 3, 2018
1910b03
Merge branch 'reactor-netty-client' of github.com:rabbitmq/hop into r…
acogoluegnes May 15, 2018
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
30 changes: 19 additions & 11 deletions src/main/java/com/rabbitmq/http/client/ReactorNettyClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class ReactorNettyClient {

private final HttpClient client;

private final String authorizationHeader;
private final Mono<String> token;

public ReactorNettyClient(String url) {
this(urlWithoutCredentials(url),
Expand All @@ -80,11 +80,7 @@ public ReactorNettyClient(String url, String username, String password) {
client = HttpClient.create(options -> options.host(uri.getHost()).port(uri.getPort()));

// FIXME make Authentication header value configurable (default being Basic)
String credentials = username + ":" + password;
byte[] credentialsAsBytes = credentials.getBytes(StandardCharsets.ISO_8859_1);
byte[] encodedBytes = Base64.getEncoder().encode(credentialsAsBytes);
String encodedCredentials = new String(encodedBytes, StandardCharsets.ISO_8859_1);
authorizationHeader = "Basic " + encodedCredentials;
this.token = createBasicAuthenticationToken(username, password);

// FIXME make SSLContext configurable when using TLS
}
Expand All @@ -94,6 +90,16 @@ private static String urlWithoutCredentials(String url) {
return StringUtils.replace(url, url1.getUserInfo() + "@", "");
}

protected Mono<String> createBasicAuthenticationToken(String username, String password) {
return Mono.fromSupplier(() -> {
String credentials = username + ":" + password;
byte[] credentialsAsBytes = credentials.getBytes(StandardCharsets.ISO_8859_1);
byte[] encodedBytes = Base64.getEncoder().encode(credentialsAsBytes);
String encodedCredentials = new String(encodedBytes, StandardCharsets.ISO_8859_1);
return "Basic " + encodedCredentials;
}).cache();
}

public Mono<OverviewResponse> getOverview() {
return doGetMono(OverviewResponse.class, "overview");
}
Expand All @@ -120,7 +126,7 @@ public Mono<HttpClientResponse> deletePolicy(String vhost, String name) {

private <T> Mono<T> doGetMono(Class<T> type, String... pathSegments) {
return client.get(uri(pathSegments), request -> Mono.just(request)
.map(this::addAuthentication)
.transform(this::addAuthorization)
.flatMap(pRequest -> pRequest.send())).transform(decode(type));
}

Expand All @@ -130,20 +136,22 @@ private <T> Flux<T> doGetFlux(Class<T> type, String... pathSegments) {

private Mono<HttpClientResponse> doPost(Object body, String... pathSegments) {
return client.put(uri(pathSegments), request -> Mono.just(request)
.map(this::addAuthentication)
.transform(this::addAuthorization)
.map(this::disableChunkTransfer)
.transform(encode(body)));
}

private Mono<HttpClientResponse> doDelete(String... pathSegments) {
return client.delete(uri(pathSegments), request -> Mono.just(request)
.map(this::addAuthentication)
.transform(this::addAuthorization)
.flatMap(HttpClientRequest::send)
);
}

private HttpClientRequest addAuthentication(HttpClientRequest request) {
return request.addHeader(HttpHeaderNames.AUTHORIZATION, authorizationHeader);
private Mono<HttpClientRequest> addAuthorization(Mono<HttpClientRequest> request) {
return Mono
.zip(request, token)
.map(tuple -> tuple.getT1().addHeader(HttpHeaderNames.AUTHORIZATION, tuple.getT2()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the token is that class property, therefore this. would help.
And if it is that, it looks like

.doOnNext(r -> r.addHeader(HttpHeaderNames.AUTHORIZATION, this.token))

would enough and much efficient.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I see what you mean with zip(). That's because token is a Mono.
Well, I think .block() especially for cached in-memory value isn't evil here at all.
I just mean that I don't see reason in extra zip just for resolving credential on demand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

token updated to this.token.
token is a Mono<String>, so the point here is to get the token only when needed and potentially a value that can change between calls. The solution you suggest would work only if the token doesn't change once the instance has been created. This is actually the case by default (the Authorization header uses username / password digest). Does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but you use .cache() there. I think this will eliminate any your attempts to change credentials at runtime.

Am I missing anything else ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right, the current default implementation is static and may be the one used 99% of the time. I plan to add a way to provide a custom Mono<String> token when creating the client, to address any case (e.g. dynamic token of some kind). This is why the addAuthorization is implemented this way. Hope this is clearer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good. It is now. Thank you!

}

private String uri(String... pathSegments) {
Expand Down