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
Adding WebProxy support for outgoing requests #879
Conversation
/// <summary> | ||
/// Optional web proxy used when communicating with the destination server. | ||
/// </summary> | ||
public System.Net.IWebProxy WebProxy { get; init; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this would add another non-serializable type to the config model. We've been trying to limit that. Is there a reason we need to directly expose IWebProxy here? Would it be possible to expose the raw values from WebProxyConfigData here and then build the proxy instance in the client factory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, of course. I have done it this way to mimic ProxyHttpClientOptions.ClientCertificate implementation. I will remove IWebProxyConfigLoader and construct web proxy instance in client factory.
In future, we could maybe expose IWebProxy factory so user could have more power when generating web proxy instance. Similar pattern could be applied to ProxyHttpClientOptions.ClientCertificate implementation.
Thank you for your feedback!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi,
I just commited newest version. All tests are passing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth exposing all proxy options here?
This could be just a string for the address, where one could use #869 if they need more customization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have done it this way to mimic ProxyHttpClientOptions.ClientCertificate implementation.
Yeah, ClientCertificate is the other problematic property that we haven't figured out what to do with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MihaZupan If one will be able to derive from ProxyHttpClientFactory, register new implementation (as singleton) via dependency injection and override ConfigureHandler, then WebProxyOptions can be simplified if needed (by removing BypassOnLocal and UseDefaultCredentials properties).
Although, it may be easier for end-user to configure WebProxy directly from config.
I am neutral here :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Tratcher For certificate loading I would create simple configuration structure with properties:
-X509FindType
-findValue
-validOnly
This would be used for X509Certificate2Collection.Find method: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509certificate2collection.find?view=net-5.0
For more advanced scenarios one would have to derive from ProxyHttpClientFactory and override ConfigureHandler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although, it may be easier for end-user to configure WebProxy directly from config.
Right, I'm thinking in terms of how commonly such settings would be changed vs. us mirroring the SocketsHttpHandler surface here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UseDefaultCredentials seems like it will be a common need. I don't know how frequently BypassOnLocal will be used, but if we already have two options then a third is harmless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I only have a few remaining cosmetic comments.
src/ReverseProxy/Service/Proxy/Infrastructure/ProxyHttpClientFactory.cs
Outdated
Show resolved
Hide resolved
src/ReverseProxy/Service/Proxy/Infrastructure/ProxyHttpClientFactory.cs
Outdated
Show resolved
Hide resolved
|
||
/// <summary> | ||
/// true to bypass the proxy for local addresses; otherwise, false. | ||
/// If null, default value for <seealso cref="System.Net.WebProxy"/> implementation will be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is false?
|
||
/// <summary> | ||
/// Controls whether the <seealso cref="System.Net.CredentialCache.DefaultCredentials"/> are sent with requests. | ||
/// If null, default value for <seealso cref="System.Net.WebProxy"/> implementation will be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include the default (false?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
I have included internal constants with default values in WebProxyOptions. I am not relying on default values from WebProxy implementation (but currently, they should be same).
Should we leave BypassOnLocal and UseDefaultCredentials properties as nullable bool? or should we change them to non-nullable bool ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We prefer nullables in the config so an extended implementation can choose its own defaults.
…actory.cs Co-authored-by: Chris Ross <Tratcher@Outlook.com>
…actory.cs Co-authored-by: Chris Ross <Tratcher@Outlook.com>
} | ||
|
||
var options = new WebProxyOptions(); | ||
webProxyConfig.Bind(options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bind
is not used for other options, each property is read separately. Does this also need to change for consistency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional question: since Bind is using reflection, is this acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. The biggest reason not to use bind is that it messes up the linker (the setters get deleted because it can't tell they're in use). It would be better for consistency to avoid Bind regardless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! This should be now fixed.
|
||
internal const bool BypassOnLocalDefaultValue = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal const bool BypassOnLocalDefaultValue = false; |
The consumer (ProxyHttpClientFactory) gets to decide what the actual defaults are. The defaults in the doc comments reflect the defaults used by the default ProxyHttpClientFactory. (so many defaults...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Defaults should be now fixed :)
…ry implementation
…to CreateWebProxyOptions for better consistency
src/ReverseProxy/Service/Proxy/Infrastructure/ProxyHttpClientFactory.cs
Outdated
Show resolved
Hide resolved
…actory.cs Simplification for setting default value Co-authored-by: Kahbazi <akahbazi@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One comment about validation, but otherwise this looks good.
@@ -320,6 +320,8 @@ private ProxyHttpClientOptions CreateProxyHttpClientOptions(IConfigurationSectio | |||
} | |||
} | |||
|
|||
var webProxy = TryGetWebProxyOptions(section.GetSection(nameof(ProxyHttpClientOptions.WebProxy))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: Why isn't this called inline on line 336 like the others?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With newest commit, I moved web proxy parsing inline to bo more aligned with other parsing (minor cosmetic changes can be still adjusted if needed).
@@ -23,6 +23,16 @@ internal static class ConfigurationReadingExtensions | |||
return configuration[name] is string value ? TimeSpan.Parse(value, CultureInfo.InvariantCulture) : null; | |||
} | |||
|
|||
internal static Uri ReadUri(this IConfiguration configuration, string name) | |||
{ | |||
if (configuration[name] is string value && Uri.TryCreate(value, UriKind.Absolute, out var parsedUri)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've intentionally avoided the Try APIs in the config reader because we want to actively report errors. Use the normal constructor and let it throw if the value is invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense. I changed this in newest commit.
Thanks |
Hi,
I added initial WebProxy support for outgoing requests. This is useful for enterprise environments which frequently use internal web proxies.
All tests are successfully passing.
Kind regards,
Vladimir Djurić
https://vladimir.djuric.si/