Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ internal static void AddOAuthData(
"Using query parameters in the base URL is not supported for OAuth calls. Consider using AddDefaultQueryParameter instead."
);

var url = client.BuildUri(request).ToString();
var url = client.BuildUriString(request);
var queryStringStart = url.IndexOf('?');

if (queryStringStart != -1) url = url[..queryStringStart];
Expand Down
25 changes: 15 additions & 10 deletions src/RestSharp/BuildUriExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,23 @@ public static class BuildUriExtensions {
/// </summary>
/// <param name="request">Request instance</param>
/// <returns></returns>
public Uri BuildUri(RestRequest request) {
DoBuildUriValidations(client, request);
public Uri BuildUri(RestRequest request) => new(client.BuildUriString(request));

var (uri, resource) = client.Options.BaseUrl.GetUrlSegmentParamsValues(
request.Resource,
client.Options.Encode,
request.Parameters,
client.DefaultParameters
);
var mergedUri = uri.MergeBaseUrlAndResource(resource);
/// <summary>
/// Builds the URI string for the request. This method returns a string instead of a Uri object
/// to preserve unencoded characters when encode=false is specified for query parameters.
/// </summary>
/// <param name="request">Request instance</param>
/// <returns></returns>
[PublicAPI]
public string BuildUriString(RestRequest request) {
var mergedUri = client.BuildUriWithoutQueryParameters(request);
var query = client.GetRequestQuery(request);
return mergedUri.AddQueryString(query);

if (query == null) return mergedUri.AbsoluteUri;

var separator = mergedUri.AbsoluteUri.Contains('?') ? "&" : "?";
return $"{mergedUri.AbsoluteUri}{separator}{query}";
}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions src/RestSharp/Request/UriExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public static Uri MergeBaseUrlAndResource(this Uri? baseUrl, string? resource) {
public static Uri AddQueryString(this Uri uri, string? query) {
if (query == null) return uri;

var absoluteUri = uri.AbsoluteUri;
var separator = absoluteUri.Contains('?') ? "&" : "?";
var builder = new UriBuilder(uri);
builder.Query = builder.Query.Length > 1 ? $"{builder.Query[1..]}&{query}" : query;

return new($"{absoluteUri}{separator}{query}");
return builder.Uri;
}

public static UrlSegmentParamsValues GetUrlSegmentParamsValues(
Expand Down
5 changes: 3 additions & 2 deletions src/RestSharp/RestClient.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ async Task<HttpResponse> ExecuteRequestAsync(RestRequest request, CancellationTo
using var requestContent = new RequestContent(this, request);

var httpMethod = AsHttpMethod(request.Method);
var url = this.BuildUri(request);
var urlString = this.BuildUriString(request);
var url = new Uri(urlString);

using var message = new HttpRequestMessage(httpMethod, url);
using var message = new HttpRequestMessage(httpMethod, urlString);
message.Content = requestContent.BuildContent();
message.Headers.Host = Options.BaseHost;
message.Headers.CacheControl = request.CachePolicy ?? Options.CachePolicy;
Expand Down
3 changes: 1 addition & 2 deletions test/RestSharp.InteractiveTests/AuthenticationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ public static async Task Can_Authenticate_With_OAuth_Async_With_Callback(Twitter

request = new($"oauth/authorize?oauth_token={oauthToken}");

var url = client.BuildUri(request)
.ToString();
var url = client.BuildUriString(request);

Console.WriteLine($"Open this URL in the browser: {url} and complete the authentication.");
Console.Write("Enter the verifier: ");
Expand Down
13 changes: 13 additions & 0 deletions test/RestSharp.Tests.Integrated/DefaultParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,17 @@ public async Task Should_not_throw_exception_when_name_is_null() {

await client.ExecuteAsync(request);
}

[Fact]
public async Task Should_not_encode_pipe_character_when_encode_is_false() {
using var client = new RestClient(server.Url!);

var request = new RestRequest("capture");
request.AddQueryParameter("ids", "in:001|116", false);

await client.ExecuteAsync(request);

var query = _capturer.RawUrl.Split('?')[1];
query.Should().Contain("ids=in:001|116");
}
}
2 changes: 2 additions & 0 deletions test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class RequestBodyCapturer {
public bool HasBody { get; private set; }
public string Body { get; private set; }
public Uri Url { get; private set; }
public string RawUrl { get; private set; }

public bool CaptureBody(string content) {
Body = content;
Expand All @@ -23,6 +24,7 @@ public bool CaptureHeaders(IDictionary<string, string[]> headers) {
}

public bool CaptureUrl(string url) {
RawUrl = url;
Url = new(url);
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion test/RestSharp.Tests/Auth/OAuth1SignatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void Generates_correct_signature_base() {
var requestParameters = _request.Parameters.ToWebParameters().ToArray();
var parameters = new WebPairCollection();
parameters.AddRange(requestParameters);
var url = _client.BuildUri(_request).ToString();
var url = _client.BuildUriString(_request);
_workflow.RequestUrl = url;
var oauthParameters = _workflow.BuildProtectedResourceSignature(method, parameters);
oauthParameters.Parameters.AddRange(requestParameters);
Expand Down
2 changes: 1 addition & 1 deletion test/RestSharp.Tests/Auth/OAuth1Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task Can_Authenticate_OAuth1_With_Querystring_Parameters() {
authenticator.ParameterHandling = OAuthParameterHandling.UrlOrPostParameters;
await authenticator.Authenticate(client, request);

var requestUri = client.BuildUri(request);
var requestUri = new Uri(client.BuildUriString(request));
var actual = requestUri.ParseQuery().Select(x => x.Key).ToList();

actual.Should().BeEquivalentTo(expected);
Expand Down
26 changes: 14 additions & 12 deletions test/RestSharp.Tests/Parameters/UrlSegmentTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
namespace RestSharp.Tests.Parameters;

public class UrlSegmentTests {
const string BaseUrl = "http://localhost:8888/";
const string BaseUrlNoTrail = "http://localhost:8888";
const string BaseUrl = $"{BaseUrlNoTrail}/";

[Fact]
public void AddUrlSegmentWithInt() {
Expand All @@ -22,10 +23,10 @@ public void AddUrlSegmentModifiesUrlSegmentWithInt() {

var path = string.Format(pathTemplate, $"{{{name}}}");
var request = new RestRequest(path).AddUrlSegment(name, urlSegmentValue);
var expected = string.Format(pathTemplate, urlSegmentValue);
var expected = $"{BaseUrlNoTrail}{string.Format(pathTemplate, urlSegmentValue)}";

using var client = new RestClient(BaseUrl);
var actual = client.BuildUri(request).AbsolutePath;
var actual = client.BuildUriString(request);

expected.Should().BeEquivalentTo(actual);
}
Expand All @@ -38,11 +39,11 @@ public void AddUrlSegmentModifiesUrlSegmentWithString() {

var path = string.Format(pathTemplate, $"{{{name}}}");
var request = new RestRequest(path).AddUrlSegment(name, urlSegmentValue);
var expected = string.Format(pathTemplate, urlSegmentValue);
var expected = $"{BaseUrlNoTrail}{string.Format(pathTemplate, urlSegmentValue)}";

using var client = new RestClient(BaseUrl);

var actual = client.BuildUri(request).AbsolutePath;
var actual = client.BuildUriString(request);

expected.Should().BeEquivalentTo(actual);
}
Expand Down Expand Up @@ -73,14 +74,15 @@ public void UrlSegmentParameter_WithValueWithEncodedSlash_CanLeaveEncodedSlash(s

[Fact]
public void AddSameUrlSegmentTwice_ShouldReplaceFirst() {
var client = new RestClient();
var request = new RestRequest("https://api.example.com/orgs/{segment}/something");
const string host = "https://api.example.com";
var client = new RestClient();
var request = new RestRequest($"{host}/orgs/{{segment}}/something");
request.AddUrlSegment("segment", 1);
var url1 = client.BuildUri(request);
var url1 = client.BuildUriString(request);
request.AddUrlSegment("segment", 2);
var url2 = client.BuildUri(request);
url1.AbsolutePath.Should().Be("/orgs/1/something");
url2.AbsolutePath.Should().Be("/orgs/2/something");
var url2 = client.BuildUriString(request);

url1.Should().Be($"{host}/orgs/1/something");
url2.Should().Be($"{host}/orgs/2/something");
}
}
4 changes: 2 additions & 2 deletions test/RestSharp.Tests/RestRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public void RestRequest_Test_Already_Encoded() {
parameters.Should().BeEquivalentTo(expected, options => options.ExcludingMissingMembers());

using var client = new RestClient(baseUrl);
var actual = client.BuildUri(request);
actual.AbsoluteUri.Should().Be($"{baseUrl}{resource}");
var actual = client.BuildUriString(request);
actual.Should().Be($"{baseUrl}{resource}");
}

[Fact]
Expand Down
12 changes: 12 additions & 0 deletions test/RestSharp.Tests/UrlBuilderTests.Get.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ public void GET_with_empty_request_and_query_parameters_without_encoding() {
Assert.Equal(expected, output);
}

[Fact]
public void GET_with_pipe_character_in_query_parameter_without_encoding() {
var request = new RestRequest();
request.AddQueryParameter("ids", "in:001|116", false);
const string expected = $"{Base}/{Resource}?ids=in:001|116";

using var client = new RestClient($"{Base}/{Resource}");

var output = client.BuildUriString(request);
Assert.Equal(expected, output);
}

[Fact]
public void GET_with_Invalid_Url_string_throws_exception()
=> Assert.Throws<UriFormatException>(() => { _ = new RestClient("invalid url"); }
Expand Down
Loading