Skip to content

Commit

Permalink
Handle the case where appid contains at least one upperletter (#1233)
Browse files Browse the repository at this point in the history
* Handle the case where appid can contain some uppercases

Signed-off-by: Nicolas Chaussé <[email protected]>
Signed-off-by: TWEESTY <[email protected]>
Signed-off-by: Nicolas Chaussé <[email protected]>

* Add one test sample

Signed-off-by: Nicolas Chaussé <[email protected]>
Signed-off-by: TWEESTY <[email protected]>
Signed-off-by: Nicolas Chaussé <[email protected]>

* Optimization in order to not add some overhead time for the "normal" use case

Signed-off-by: TWEESTY <[email protected]>
Signed-off-by: Nicolas Chaussé <[email protected]>

* Change comment which was false

Signed-off-by: TWEESTY <[email protected]>
Signed-off-by: Nicolas Chaussé <[email protected]>

* Remove the breaking change

Signed-off-by: TWEESTY <[email protected]>
Signed-off-by: Nicolas Chaussé <[email protected]>

* Simplify according to the review

Signed-off-by: Nicolas Chaussé <[email protected]>

---------

Signed-off-by: Nicolas Chaussé <[email protected]>
Signed-off-by: TWEESTY <[email protected]>
  • Loading branch information
TWEESTY authored Feb 16, 2024
1 parent ca2fab2 commit 817b60d
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 20 deletions.
8 changes: 5 additions & 3 deletions src/Dapr.Client/DaprClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public abstract class DaprClient : IDisposable
/// </summary>
/// <param name="appId">
/// An optional <c>app-id</c>. If specified, the <c>app-id</c> will be configured as the value of
/// <see cref="HttpClient.BaseAddress" /> so that relative URIs can be used.
/// <see cref="HttpClient.BaseAddress" /> so that relative URIs can be used. It is mandatory to set this parameter if your app-id contains at least one upper letter.
/// If some requests use absolute URL with an app-id which contains at least one upper letter, it will not work, the workaround is to create one HttpClient for each app-id with the app-ip parameter set.
/// </param>
/// <param name="daprEndpoint">The HTTP endpoint of the Dapr process to use for service invocation calls.</param>
/// <param name="daprApiToken">The token to be added to all request headers to Dapr runtime.</param>
Expand All @@ -80,7 +81,8 @@ public static HttpClient CreateInvokeHttpClient(string appId = null, string dapr
var handler = new InvocationHandler()
{
InnerHandler = new HttpClientHandler(),
DaprApiToken = daprApiToken
DaprApiToken = daprApiToken,
DefaultAppId = appId,
};

if (daprEndpoint is string)
Expand Down Expand Up @@ -210,7 +212,7 @@ public abstract Task PublishEventAsync(
string topicName,
Dictionary<string, string> metadata,
CancellationToken cancellationToken = default);

/// <summary>
/// // Bulk Publishes multiple events to the specified topic.
/// </summary>
Expand Down
20 changes: 18 additions & 2 deletions src/Dapr.Client/InvocationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Copyright 2021 The Dapr Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -82,6 +82,12 @@ public string DaprEndpoint
}
}

/// <summary>
/// Gets or sets the default AppId used for service invocation
/// </summary>
/// <returns>The AppId used for service invocation</returns>
public string? DefaultAppId { get; set; }

// Internal for testing
internal string? DaprApiToken
{
Expand Down Expand Up @@ -128,13 +134,23 @@ internal bool TryRewriteUri(Uri? uri, [NotNullWhen(true)] out Uri? rewritten)
return false;
}

string host;

if (this.DefaultAppId is not null && uri.Host.Equals(this.DefaultAppId, StringComparison.InvariantCultureIgnoreCase))
{
host = this.DefaultAppId;
}
else
{
host = uri.Host;
}

var builder = new UriBuilder(uri)
{
Scheme = this.parsedEndpoint.Scheme,
Host = this.parsedEndpoint.Host,
Port = this.parsedEndpoint.Port,
Path = $"/v1.0/invoke/{uri.Host}/method" + uri.AbsolutePath,
Path = $"/v1.0/invoke/{host}/method" + uri.AbsolutePath,
};

rewritten = builder.Uri;
Expand Down
2 changes: 1 addition & 1 deletion test/Dapr.Client.Test/DaprClientTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Copyright 2021 The Dapr Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
86 changes: 72 additions & 14 deletions test/Dapr.Client.Test/InvocationHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Copyright 2021 The Dapr Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,8 +30,8 @@ public class InvocationHandlerTests
public void DaprEndpoint_InvalidScheme()
{
var handler = new InvocationHandler();
var ex = Assert.Throws<ArgumentException>(() =>
{
var ex = Assert.Throws<ArgumentException>(() =>
{
handler.DaprEndpoint = "ftp://localhost:3500";
});

Expand All @@ -43,7 +43,7 @@ public void DaprEndpoint_InvalidUri()
{
var handler = new InvocationHandler();
Assert.Throws<UriFormatException>(() =>
{
{
handler.DaprEndpoint = "";
});

Expand Down Expand Up @@ -79,30 +79,63 @@ public void TryRewriteUri_FailsForRelativeUris()
}

[Theory]
[InlineData("http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
public void TryRewriteUri_RewritesUriToDaprInvoke(string uri, string expected)
[InlineData(null, "http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("bank", "http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://bank", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("invalid", "http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://Bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://Bank", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("bank", "http://Bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("invalid", "http://Bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("bank", "http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("invalid", "http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://Bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://Bank:3939", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("invalid", "http://Bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("app-id.with.dots", "http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("invalid", "http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData(null, "http://App-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("App-id.with.dots", "http://App-id.with.dots", "https://some.host:3499/v1.0/invoke/App-id.with.dots/method/")]
[InlineData("invalid", "http://App-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData(null, "http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("bank", "http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("invalid", "http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://Bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://Bank:3939/", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("invalid", "http://Bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("bank", "http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("invalid", "http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData(null, "http://Bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("Bank", "http://Bank:3939/some/path", "https://some.host:3499/v1.0/invoke/Bank/method/some/path")]
[InlineData("invalid", "http://Bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData(null, "http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData("bank", "http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData("invalid", "http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData(null, "http://Bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData("Bank", "http://Bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/Bank/method/some/path?q=test&p=another#fragment")]
[InlineData("invalid", "http://Bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
public void TryRewriteUri_WithNoAppId_RewritesUriToDaprInvoke(string? appId, string uri, string expected)
{
var handler = new InvocationHandler()
{
DaprEndpoint = "https://some.host:3499",
DefaultAppId = appId,
};

Assert.True(handler.TryRewriteUri(new Uri(uri), out var rewritten));
Assert.Equal(expected, rewritten!.OriginalString);
}

[Fact]
public async Task SendAsync_InvalidUri_ThrowsException()
public async Task SendAsync_InvalidNotSetUri_ThrowsException()
{
var handler = new InvocationHandler();
var ex = await Assert.ThrowsAsync<ArgumentException>(async () =>
{
await CallSendAsync(handler, new HttpRequestMessage(){ }); // No URI set
await CallSendAsync(handler, new HttpRequestMessage() { }); // No URI set
});

Assert.Contains("The request URI '' is not a valid Dapr service invocation destination.", ex.Message);
Expand Down Expand Up @@ -132,6 +165,31 @@ public async Task SendAsync_RewritesUri()
Assert.False(request.Headers.TryGetValues("dapr-api-token", out _));
}

[Fact]
public async Task SendAsync_RewritesUri_AndAppId()
{
var uri = "http://bank/accounts/17?";

var capture = new CaptureHandler();
var handler = new InvocationHandler()
{
InnerHandler = capture,

DaprEndpoint = "https://localhost:5000",
DaprApiToken = null,
DefaultAppId = "Bank"
};

var request = new HttpRequestMessage(HttpMethod.Post, uri);
var response = await CallSendAsync(handler, request);

Assert.Equal("https://localhost:5000/v1.0/invoke/Bank/method/accounts/17?", capture.RequestUri?.OriginalString);
Assert.Null(capture.DaprApiToken);

Assert.Equal(uri, request.RequestUri?.OriginalString);
Assert.False(request.Headers.TryGetValues("dapr-api-token", out _));
}

[Fact]
public async Task SendAsync_RewritesUri_AndAddsApiToken()
{
Expand Down Expand Up @@ -164,7 +222,7 @@ private async Task<HttpResponseMessage> CallSendAsync(InvocationHandler handler,

try
{
return await (Task<HttpResponseMessage>)method!.Invoke(handler, new object[]{ message, cancellationToken, })!;
return await (Task<HttpResponseMessage>)method!.Invoke(handler, new object[] { message, cancellationToken, })!;
}
catch (TargetInvocationException tie) // reflection always adds an extra layer of exceptions.
{
Expand Down

0 comments on commit 817b60d

Please sign in to comment.