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

4.0.0-pre4 #767

Merged
merged 30 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4d6c9c5
Add AppendQueryParam(s) methods
Marusyk May 13, 2022
56038e7
test for #683
tmenier Dec 21, 2022
2fe53dc
Moved guts of SendAsync from FlrulRequest to FlurlClient
tmenier Dec 22, 2022
6c13026
#683 use configured HttpClient when allowing "real" HTTP in tests
tmenier Dec 22, 2022
6a3e834
Remove space from filename
coenvdwel Dec 24, 2022
9995a76
#736 drop IHttpClientFactory
tmenier Dec 27, 2022
5667584
#738 refactoring, mostly around simplifying FlurlRequest
tmenier Dec 30, 2022
b4318ab
happy new year
tmenier Jan 2, 2023
9b77721
Merge pull request #737 from coenvdwel/dev
tmenier Sep 5, 2023
dae613a
Fixed validation of complex URLs
Janek91 Aug 29, 2023
e35478c
Merge pull request #761 from Janek91/UrlValidationFix
tmenier Sep 6, 2023
48256ed
#764 ConfigureRequest -> WithSettings
Sep 12, 2023
da3694b
Merge remote-tracking branch 'origin/dev' into dev
Sep 12, 2023
dd4995f
#462 Url.IsValid quirks
Sep 13, 2023
658dbf6
downgrade test adapter to support net461
Sep 13, 2023
1937351
#462 take 3 - I think it's way simpler than we made it!
Sep 14, 2023
b64ab95
#639 support for different HTTP versions
Sep 14, 2023
a3df496
oops, test carelessness
Sep 14, 2023
b941ecc
Merge branch 'dev' into rmarusyk/688
tmenier Sep 15, 2023
b5768a9
Merge pull request #689 from Marusyk/rmarusyk/688
tmenier Sep 15, 2023
29df951
#688 (needed to run code gen)
Sep 15, 2023
69b3b1c
#370 SetQueryParams bug with duplicate keys
Sep 15, 2023
52e6f78
#650 Flurl shouldn't dispose request message
Sep 18, 2023
5a9f2d6
#758 CookieJar persistence
Sep 19, 2023
98aeae3
#740 bug: extra space in header values
Sep 19, 2023
096f91d
rename dir Test -> test
Sep 29, 2023
30372fb
copy HttpClient settings to FlurlClient when provided directly
Oct 2, 2023
7e5f533
version bumps (4.0-pre4)
Oct 8, 2023
a6b1817
Test -> test name change needed sln file to make build happy
Oct 8, 2023
c455f74
test fix
Oct 8, 2023
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 Flurl.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flurl.Http", "src\Flurl.Htt
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{86A5ACB4-F3B3-4395-A5D5-924C9F35F628}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flurl.Test", "Test\Flurl.Test\Flurl.Test.csproj", "{DF68EB0E-9566-4577-B709-291520383F8D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flurl.Test", "test\Flurl.Test\Flurl.Test.csproj", "{DF68EB0E-9566-4577-B709-291520383F8D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{B6BF9238-4541-4E1F-955E-C95F1C2A1F46}"
ProjectSection(SolutionItems) = preProject
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Todd Menier
Copyright (c) 2023 Todd Menier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
29 changes: 27 additions & 2 deletions src/Flurl.CodeGen/Metadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,31 @@ public static IEnumerable<ExtensionMethod> GetUrlReturningExtensions(MethodArg e
yield return Create("SetQueryParams", "Creates a new Url object from the string and adds multiple parameters without values to the query.")
.AddArg("names", "params string[]", "Names of query parameters");

yield return Create("AppendQueryParam", "Creates a new Url object from the string and adds a parameter to the query.")
.AddArg("name", "string", "Name of query parameter")
.AddArg("value", "object", "Value of query parameter")
.AddArg("nullValueHandling", "NullValueHandling", "Indicates how to handle null values. Defaults to Remove (any existing)", "NullValueHandling.Remove");

yield return Create("AppendQueryParam", "Creates a new Url object from the string and adds a parameter to the query.")
.AddArg("name", "string", "Name of query parameter")
.AddArg("value", "string", "Value of query parameter")
.AddArg("isEncoded", "bool", "Set to true to indicate the value is already URL-encoded. Defaults to false.", "false")
.AddArg("nullValueHandling", "NullValueHandling", "Indicates how to handle null values. Defaults to Remove (any existing).", "NullValueHandling.Remove");

yield return Create("AppendQueryParam", "Creates a new Url object from the string and adds a parameter without a value to the query.")
.AddArg("name", "string", "Name of query parameter");

yield return Create("AppendQueryParam", "Creates a new Url object from the string, parses values object into name/value pairs, and adds them to the query, overwriting any that already exist.")
.AddArg("values", "object", "Typically an anonymous object, ie: new { x = 1, y = 2 }")
.AddArg("nullValueHandling", "NullValueHandling", "Indicates how to handle null values. Defaults to Remove (any existing)", "NullValueHandling.Remove");

yield return Create("AppendQueryParam", "Creates a new Url object from the string and adds multiple parameters without values to the query.")
.AddArg("names", "IEnumerable<string>", "Names of query parameters.");

yield return Create("AppendQueryParam", "Creates a new Url object from the string and adds multiple parameters without values to the query.")
.AddArg("names", "params string[]", "Names of query parameters");


yield return Create("RemoveQueryParam", "Creates a new Url object from the string and removes a name/value pair from the query by name.")
.AddArg("name", "string", "Query string parameter name to remove");

Expand Down Expand Up @@ -98,15 +123,15 @@ public static IEnumerable<ExtensionMethod> GetRequestReturningExtensions(MethodA
.AddArg("name", "string", "The cookie name.")
.AddArg("value", "object", "The cookie value.");
yield return Create("WithCookies", "Creates a new FlurlRequest and adds name-value pairs to its Cookie header based on property names/values of the provided object, or keys/values if object is a dictionary. " +
"To automatically maintain a cookie \"session\", consider using a CookieJar or CookieSession instead.")
"To automatically maintain a cookie \"session\", consider using a CookieJar or CookieSession instead.")
.AddArg("values", "object", "Names/values of HTTP cookies to set. Typically an anonymous object or IDictionary.");
yield return Create("WithCookies", "Creates a new FlurlRequest and sets the CookieJar associated with this request, which will be updated with any Set-Cookie headers present in the response and is suitable for reuse in subsequent requests.")
.AddArg("cookieJar", "CookieJar", "The CookieJar.");
yield return Create("WithCookies", "Creates a new FlurlRequest and associates it with a new CookieJar, which will be updated with any Set-Cookie headers present in the response and is suitable for reuse in subsequent requests.")
.AddArg("cookieJar", "CookieJar", "The created CookieJar, which can be reused in subsequent requests.", isOut: true);

// settings extensions
yield return Create("ConfigureRequest", "Creates a new FlurlRequest and allows changing its Settings inline.")
yield return Create("WithSettings", "Creates a new FlurlRequest and allows changing its Settings inline.")
.AddArg("action", "Action<FlurlHttpSettings>", "A delegate defining the Settings changes.");
yield return Create("WithTimeout", "Creates a new FlurlRequest and sets the request timeout.")
.AddArg("timespan", "TimeSpan", "Time to wait before the request times out.");
Expand Down
50 changes: 0 additions & 50 deletions src/Flurl.Http/Configuration/DefaultHttpClientFactory.cs

This file was deleted.

39 changes: 39 additions & 0 deletions src/Flurl.Http/Configuration/FlurlClientFactoryBase.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Net.Http;
using System.Net;

namespace Flurl.Http.Configuration
{
Expand Down Expand Up @@ -53,5 +55,42 @@ public void Dispose() {
}
_clients.Clear();
}

/// <summary>
/// Override in custom factory to customize the creation of HttpClient used in all Flurl HTTP calls
/// (except when one is passed explicitly to the FlurlClient constructor). In order not to lose
/// Flurl.Http functionality, it is recommended to call base.CreateClient and customize the result.
/// </summary>
public virtual HttpClient CreateHttpClient(HttpMessageHandler handler) {
return new HttpClient(handler) {
// Timeouts handled per request via FlurlHttpSettings.Timeout
Timeout = System.Threading.Timeout.InfiniteTimeSpan
};
}

/// <summary>
/// Override in custom factory to customize the creation of the top-level HttpMessageHandler used in all
/// Flurl HTTP calls (except when an HttpClient is passed explicitly to the FlurlClient constructor).
/// In order not to lose Flurl.Http functionality, it is recommended to call base.CreateMessageHandler, and
/// either customize the returned HttpClientHandler, or set it as the InnerHandler of a DelegatingHandler.
/// </summary>
public virtual HttpMessageHandler CreateMessageHandler() {
var httpClientHandler = new HttpClientHandler();

// flurl has its own mechanisms for managing cookies and redirects

try { httpClientHandler.UseCookies = false; }
catch (PlatformNotSupportedException) { } // look out for WASM platforms (#543)

if (httpClientHandler.SupportsRedirectConfiguration)
httpClientHandler.AllowAutoRedirect = false;

if (httpClientHandler.SupportsAutomaticDecompression) {
// #266
// deflate not working? see #474
httpClientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}
return httpClientHandler;
}
}
}
47 changes: 13 additions & 34 deletions src/Flurl.Http/Configuration/FlurlHttpSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public FlurlHttpSettings() {
Redirects = new RedirectSettings(this);
ResetDefaults();
}

/// <summary>
/// Gets or sets the default values to fall back on when values are not explicitly set on this instance.
/// </summary>
Expand All @@ -41,7 +42,15 @@ public TimeSpan? Timeout {
}

/// <summary>
/// Gets or sets a pattern representing a range of HTTP status codes which (in addtion to 2xx) will NOT result in Flurl.Http throwing an Exception.
/// Gets or sets the HTTP version to be used. Default is "1.1".
/// </summary>
public string HttpVersion {
get => Get<Version>()?.ToString();
set => Set(Version.TryParse(value, out var v) ? v : throw new ArgumentException("Invalid HTTP version: " + value));
}

/// <summary>
/// Gets or sets a pattern representing a range of HTTP status codes which (in addition to 2xx) will NOT result in Flurl.Http throwing an Exception.
/// Examples: "3xx", "100,300,600", "100-299,6xx", "*" (allow everything)
/// 2xx will never throw regardless of this setting.
/// </summary>
Expand Down Expand Up @@ -169,26 +178,10 @@ internal void Set<T>(T value, [CallerMemberName]string propName = null) {
}
}

/// <summary>
/// Client-level settings for Flurl.Http
/// </summary>
public class ClientFlurlHttpSettings : FlurlHttpSettings
{
/// <summary>
/// Gets or sets a factory used to create the HttpClient and HttpMessageHandler used for HTTP calls.
/// Whenever possible, custom factory implementations should inherit from DefaultHttpClientFactory,
/// only override the method(s) needed, call the base method, and modify the result.
/// </summary>
public IHttpClientFactory HttpClientFactory {
get => Get<IHttpClientFactory>();
set => Set(value);
}
}

/// <summary>
/// Global default settings for Flurl.Http
/// </summary>
public class GlobalFlurlHttpSettings : ClientFlurlHttpSettings
public class GlobalFlurlHttpSettings : FlurlHttpSettings
{
internal GlobalFlurlHttpSettings() {
ResetDefaults();
Expand All @@ -199,7 +192,7 @@ internal GlobalFlurlHttpSettings() {
/// </summary>
public override FlurlHttpSettings Defaults {
get => null;
set => throw new Exception("Global settings cannot be backed by any higher-level defauts.");
set => throw new Exception("Global settings cannot be backed by any higher-level defaults.");
}

/// <summary>
Expand All @@ -217,29 +210,15 @@ public IFlurlClientFactory FlurlClientFactory {
public override void ResetDefaults() {
base.ResetDefaults();
Timeout = TimeSpan.FromSeconds(100); // same as HttpClient
HttpVersion = "1.1";
JsonSerializer = new DefaultJsonSerializer();
UrlEncodedSerializer = new DefaultUrlEncodedSerializer();
FlurlClientFactory = new DefaultFlurlClientFactory();
HttpClientFactory = new DefaultHttpClientFactory();
Redirects.Enabled = true;
Redirects.AllowSecureToInsecure = false;
Redirects.ForwardHeaders = false;
Redirects.ForwardAuthorizationHeader = false;
Redirects.MaxAutoRedirects = 10;
}
}

/// <summary>
/// Settings overrides within the context of an HttpTest
/// </summary>
public class TestFlurlHttpSettings : ClientFlurlHttpSettings
{
/// <summary>
/// Resets all test settings to their Flurl.Http-defined default values.
/// </summary>
public override void ResetDefaults() {
base.ResetDefaults();
HttpClientFactory = new TestHttpClientFactory();
}
}
}
29 changes: 26 additions & 3 deletions src/Flurl.Http/Configuration/IFlurlClientFactory.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
using System;
using System.Net.Http;
using System.Runtime.CompilerServices;

namespace Flurl.Http.Configuration
{
/// <summary>
/// Interface for defining a strategy for creating, caching, and reusing IFlurlClient instances and,
/// by proxy, their underlying HttpClient instances.
/// Interface for defining a strategy for creating, caching, and reusing IFlurlClient instances and
/// their underlying HttpClient instances. It is generally preferable to derive from FlurlClientFactoryBase
/// and only override methods as needed, rather than implementing this interface from scratch.
/// </summary>
public interface IFlurlClientFactory : IDisposable
{
/// <summary>
/// Strategy to create a FlurlClient or reuse an exisitng one, based on URL being called.
/// Strategy to create a FlurlClient or reuse an existing one, based on the URL being called.
/// </summary>
/// <param name="url">The URL being called.</param>
/// <returns></returns>
IFlurlClient Get(Url url);

/// <summary>
/// Defines how HttpClient should be instantiated and configured by default. Do NOT attempt
/// to cache/reuse HttpClient instances here - that should be done at the FlurlClient level
/// via a custom FlurlClientFactory that gets registered globally.
/// </summary>
/// <param name="handler">The HttpMessageHandler used to construct the HttpClient.</param>
/// <returns></returns>
HttpClient CreateHttpClient(HttpMessageHandler handler);

/// <summary>
/// Defines how the HttpMessageHandler used by HttpClients that are created by
/// this factory should be instantiated and configured.
/// </summary>
/// <returns></returns>
HttpMessageHandler CreateMessageHandler();
}

/// <summary>
Expand All @@ -39,5 +57,10 @@ public static IFlurlClientFactory ConfigureClient(this IFlurlClientFactory facto
}
return factory;
}

/// <summary>
/// Creates an HttpClient with the HttpMessageHandler returned from this factory's CreateMessageHandler method.
/// </summary>
public static HttpClient CreateHttpClient(this IFlurlClientFactory fac) => fac.CreateHttpClient(fac.CreateMessageHandler());
}
}
28 changes: 0 additions & 28 deletions src/Flurl.Http/Configuration/IHttpClientFactory.cs

This file was deleted.

Loading