Before

1using System;
2using System.IO;
3using System.Net;
4using System.Net.Http;
5using System.Net.Security;
6using System.Net.Sockets;
7using System.Text;
8using System.Threading;
9using System.Threading.Tasks;
10using NzbDrone.Common.Cache;
11using NzbDrone.Common.Extensions;
…lines 12–244 unchanged (233 lines)
245 }
246
247 private CredentialCache GetCredentialCache()
248 {
249 return _credentialCache.Get("credentialCache", () => new CredentialCache());
250 }
251
252 private static async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
253 {
254 // Until .NET supports an implementation of Happy Eyeballs (https://tools.ietf.org/html/rfc8305#section-2), let's make IPv4 fallback work in a simple way.
255 // This issue is being tracked at https://github.com/dotnet/runtime/issues/26177 and expected to be fixed in .NET 6.
256 if (useIPv6)
257 {
…lines 258–268 unchanged (11 lines)
269 }
270
271 return await attemptConnection(AddressFamily.InterNetworkV6, context, localToken);
272 }
273 catch
274 {
275 // very naively fallback to ipv4 permanently for this execution based on the response of the first connection attempt.
276 // note that this may cause users to eventually get switched to ipv4 (on a random failure when they are switching networks, for instance)
277 // but in the interest of keeping this implementation simple, this is acceptable.
278 useIPv6 = false;
279 }
280 finally
281 {
282 hasResolvedIPv6Availability = true;
283 }
284 }
…lines 285–315 unchanged (31 lines)

After

1using System;
2using System.IO;
3using System.Linq;
4using System.Net;
5using System.Net.Http;
6using System.Net.NetworkInformation;
7using System.Net.Security;
8using System.Net.Sockets;
9using System.Text;
10using System.Threading;
11using System.Threading.Tasks;
12using NzbDrone.Common.Cache;
…lines 13–247 unchanged (235 lines)
248
249 private CredentialCache GetCredentialCache()
250 {
251 return _credentialCache.Get("credentialCache", () => new CredentialCache());
252 }
253
254 private static bool HasRoutableIPv4Address()
255 {
256 // Get all IPv4 addresses from all interfaces and return true if there are any with non-loopback addresses
257 var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
258
259 return networkInterfaces.Any(ni =>
260 ni.OperationalStatus == OperationalStatus.Up &&
261 ni.GetIPProperties().UnicastAddresses.Any(ip =>
262 ip.Address.AddressFamily == AddressFamily.InterNetwork &&
263 !IPAddress.IsLoopback(ip.Address)));
264 }
265
266 private static async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
267 {
268 // Until .NET supports an implementation of Happy Eyeballs (https://tools.ietf.org/html/rfc8305#section-2), let's make IPv4 fallback work in a simple way.
269 // This issue is being tracked at https://github.com/dotnet/runtime/issues/26177 and expected to be fixed in .NET 6.
270 if (useIPv6)
…lines 271–282 unchanged (12 lines)
283 }
284
285 return await attemptConnection(AddressFamily.InterNetworkV6, context, localToken);
286 }
287 catch
288 {
289 // Do not retry IPv6 if a routable IPv4 address is available, otherwise continue to attempt IPv6 connections.
290 useIPv6 = !HasRoutableIPv4Address();
291 }
292 finally
293 {
294 hasResolvedIPv6Availability = true;
295 }
296 }
…lines 297–327 unchanged (31 lines)

Before

compilation_unit
using_directive
using "using"
identifier "System"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "IO"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Net"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "Http"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "Security"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "Sockets"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Text"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Threading"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Threading"
. "."
identifier "Tasks"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Cache"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Extensions"
; ";"
using_directive
using "using"
qualified_name
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Http"
. "."
identifier "Proxy"
; ";"
namespace_declaration
namespace "namespace"
qualified_name
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Http"
. "."
identifier "Dispatchers"
declaration_list
{ "{"
class_declaration
modifier
public "public"
class "class"
identifier "ManagedHttpDispatcher"
base_list
: ":"
identifier "IHttpDispatcher"
declaration_list
{ "{"
field_declaration
modifier
private "private"
modifier
const "const"
variable_declaration
predefined_type "string"
variable_declarator
identifier "NO_PROXY_KEY"
= "="
string_literal
" "\""
string_literal_content "no-proxy"
" "\""
; ";"
field_declaration
modifier
private "private"
modifier
const "const"
variable_declaration
predefined_type "int"
variable_declarator
identifier "connection_establish_timeout"
= "="
integer_literal "2000"
; ";"
field_declaration
modifier
private "private"
modifier
static "static"
variable_declaration
predefined_type "bool"
variable_declarator
identifier "useIPv6"
= "="
member_access_expression
identifier "Socket"
. "."
identifier "OSSupportsIPv6"
; ";"
field_declaration
modifier
private "private"
modifier
static "static"
variable_declaration
predefined_type "bool"
variable_declarator
identifier "hasResolvedIPv6Availability"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "IHttpProxySettingsProvider"
variable_declarator
identifier "_proxySettingsProvider"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "ICreateManagedWebProxy"
variable_declarator
identifier "_createManagedWebProxy"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "ICertificateValidationService"
variable_declarator
identifier "_certificateValidationService"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "IUserAgentBuilder"
variable_declarator
identifier "_userAgentBuilder"
; ";"
field_declaration (+24 nodes collapsed)
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
generic_name
identifier "ICached"
type_argument_list
< "<"
identifier "CredentialCache"
> ">"
variable_declarator
identifier "_credentialCache"
; ";"
constructor_declaration (+116 nodes collapsed)
method_declaration (+858 nodes collapsed)
method_declaration (+87 nodes collapsed)
method_declaration (+194 nodes collapsed)
method_declaration (+518 nodes collapsed)
method_declaration (+82 nodes collapsed)
method_declaration (+40 nodes collapsed)
method_declaration
modifier
private "private"
modifier
static "static"
modifier
async "async"
generic_name
identifier "ValueTask"
type_argument_list
< "<"
identifier "Stream"
> ">"
identifier "onConnect"
parameter_list
( "("
parameter
identifier "SocketsHttpConnectionContext"
identifier "context"
, ","
parameter
identifier "CancellationToken"
identifier "cancellationToken"
) ")"
block
{ "{"
comment "// Until .NET supports an implementation of Happy Eyeballs ("...
comment "// This issue is being tracked at https://github.com/dotnet/"...
if_statement
if "if"
( "("
identifier "useIPv6"
) ")"
block
{ "{"
try_statement
try "try"
block (+93 nodes collapsed)
catch_clause
catch "catch"
block
{ "{"
comment "// very naively fallback to ipv4 permanently for this execut"...
comment "// note that this may cause users to eventually get switched"...
comment "// but in the interest of keeping this implementation simple"...
expression_statement
assignment_expression
identifier "useIPv6"
= "="
boolean_literal
false "false"
; ";"
} "}"
finally_clause
finally "finally"
block
{ "{"
expression_statement
assignment_expression
identifier "hasResolvedIPv6Availability"
= "="
boolean_literal
true "true"
; ";"
} "}"
} "}"
comment "// fallback to IPv4."
return_statement (+21 nodes collapsed)
} "}"
method_declaration (+141 nodes collapsed)
} "}"
} "}"

After

compilation_unit
using_directive
using "using"
identifier "System"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "IO"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Linq"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Net"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "Http"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "NetworkInformation"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "Security"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Net"
. "."
identifier "Sockets"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Text"
; ";"
using_directive
using "using"
qualified_name
identifier "System"
. "."
identifier "Threading"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "System"
. "."
identifier "Threading"
. "."
identifier "Tasks"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Cache"
; ";"
using_directive
using "using"
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Extensions"
; ";"
using_directive
using "using"
qualified_name
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Http"
. "."
identifier "Proxy"
; ";"
namespace_declaration
namespace "namespace"
qualified_name
qualified_name
qualified_name
identifier "NzbDrone"
. "."
identifier "Common"
. "."
identifier "Http"
. "."
identifier "Dispatchers"
declaration_list
{ "{"
class_declaration
modifier
public "public"
class "class"
identifier "ManagedHttpDispatcher"
base_list
: ":"
identifier "IHttpDispatcher"
declaration_list
{ "{"
field_declaration
modifier
private "private"
modifier
const "const"
variable_declaration
predefined_type "string"
variable_declarator
identifier "NO_PROXY_KEY"
= "="
string_literal
" "\""
string_literal_content "no-proxy"
" "\""
; ";"
field_declaration
modifier
private "private"
modifier
const "const"
variable_declaration
predefined_type "int"
variable_declarator
identifier "connection_establish_timeout"
= "="
integer_literal "2000"
; ";"
field_declaration
modifier
private "private"
modifier
static "static"
variable_declaration
predefined_type "bool"
variable_declarator
identifier "useIPv6"
= "="
member_access_expression
identifier "Socket"
. "."
identifier "OSSupportsIPv6"
; ";"
field_declaration
modifier
private "private"
modifier
static "static"
variable_declaration
predefined_type "bool"
variable_declarator
identifier "hasResolvedIPv6Availability"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "IHttpProxySettingsProvider"
variable_declarator
identifier "_proxySettingsProvider"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "ICreateManagedWebProxy"
variable_declarator
identifier "_createManagedWebProxy"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "ICertificateValidationService"
variable_declarator
identifier "_certificateValidationService"
; ";"
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
identifier "IUserAgentBuilder"
variable_declarator
identifier "_userAgentBuilder"
; ";"
field_declaration (+24 nodes collapsed)
field_declaration
modifier
private "private"
modifier
readonly "readonly"
variable_declaration
generic_name
identifier "ICached"
type_argument_list
< "<"
identifier "CredentialCache"
> ">"
variable_declarator
identifier "_credentialCache"
; ";"
constructor_declaration (+116 nodes collapsed)
method_declaration (+858 nodes collapsed)
method_declaration (+87 nodes collapsed)
method_declaration (+194 nodes collapsed)
method_declaration (+518 nodes collapsed)
method_declaration (+82 nodes collapsed)
method_declaration (+40 nodes collapsed)
method_declaration
modifier
private "private"
modifier
static "static"
predefined_type "bool"
identifier "HasRoutableIPv4Address"
parameter_list
( "("
) ")"
block
{ "{"
comment "// Get all IPv4 addresses from all interfaces and return tru"...
local_declaration_statement
variable_declaration
implicit_type
var "var"
variable_declarator
identifier "networkInterfaces"
= "="
invocation_expression
member_access_expression
identifier "NetworkInterface"
. "."
identifier "GetAllNetworkInterfaces"
argument_list
( "("
) ")"
; ";"
return_statement
return "return"
invocation_expression
member_access_expression
identifier "networkInterfaces"
. "."
identifier "Any"
argument_list
( "("
argument
lambda_expression
implicit_parameter "ni"
=> "=>"
binary_expression
binary_expression
member_access_expression
identifier "ni"
. "."
identifier "OperationalStatus"
== "=="
member_access_expression
identifier "OperationalStatus"
. "."
identifier "Up"
&& "&&"
invocation_expression
member_access_expression
member_access_expression
invocation_expression
member_access_expression
identifier "ni"
. "."
identifier "GetIPProperties"
argument_list
( "("
) ")"
. "."
identifier "UnicastAddresses"
. "."
identifier "Any"
argument_list
( "("
argument
lambda_expression
implicit_parameter "ip"
=> "=>"
binary_expression
binary_expression
member_access_expression
member_access_expression
identifier "ip"
. "."
identifier "Address"
. "."
identifier "AddressFamily"
== "=="
member_access_expression
identifier "AddressFamily"
. "."
identifier "InterNetwork"
&& "&&"
prefix_unary_expression
! "!"
invocation_expression
member_access_expression
identifier "IPAddress"
. "."
identifier "IsLoopback"
argument_list
( "("
argument
member_access_expression
identifier "ip"
. "."
identifier "Address"
) ")"
) ")"
) ")"
; ";"
} "}"
method_declaration
modifier
private "private"
modifier
static "static"
modifier
async "async"
generic_name
identifier "ValueTask"
type_argument_list
< "<"
identifier "Stream"
> ">"
identifier "onConnect"
parameter_list
( "("
parameter
identifier "SocketsHttpConnectionContext"
identifier "context"
, ","
parameter
identifier "CancellationToken"
identifier "cancellationToken"
) ")"
block
{ "{"
comment "// Until .NET supports an implementation of Happy Eyeballs ("...
comment "// This issue is being tracked at https://github.com/dotnet/"...
if_statement
if "if"
( "("
identifier "useIPv6"
) ")"
block
{ "{"
try_statement
try "try"
block (+93 nodes collapsed)
catch_clause
catch "catch"
block
{ "{"
comment "// Do not retry IPv6 if a routable IPv4 address is available"...
expression_statement
assignment_expression
identifier "useIPv6"
= "="
prefix_unary_expression
! "!"
invocation_expression
identifier "HasRoutableIPv4Address"
argument_list
( "("
) ")"
; ";"
} "}"
finally_clause
finally "finally"
block
{ "{"
expression_statement
assignment_expression
identifier "hasResolvedIPv6Availability"
= "="
boolean_literal
true "true"
; ";"
} "}"
} "}"
comment "// fallback to IPv4."
return_statement (+21 nodes collapsed)
} "}"
method_declaration (+141 nodes collapsed)
} "}"
} "}"