@@ -17,95 +17,50 @@ internal class ConfigurationReader
17
17
private const string UrlKey = "Url" ;
18
18
private const string Latin1RequestHeadersKey = "Latin1RequestHeaders" ;
19
19
20
- private IConfiguration _configuration ;
21
- private IDictionary < string , CertificateConfig > _certificates ;
22
- private IList < EndpointConfig > _endpoints ;
23
- private EndpointDefaults _endpointDefaults ;
24
- private bool ? _latin1RequestHeaders ;
20
+ private readonly IConfiguration _configuration ;
25
21
26
22
public ConfigurationReader ( IConfiguration configuration )
27
23
{
28
24
_configuration = configuration ?? throw new ArgumentNullException ( nameof ( configuration ) ) ;
25
+ Certificates = ReadCertificates ( ) ;
26
+ EndpointDefaults = ReadEndpointDefaults ( ) ;
27
+ Endpoints = ReadEndpoints ( ) ;
28
+ Latin1RequestHeaders = _configuration . GetValue < bool > ( Latin1RequestHeadersKey ) ;
29
29
}
30
30
31
- public IDictionary < string , CertificateConfig > Certificates
32
- {
33
- get
34
- {
35
- if ( _certificates == null )
36
- {
37
- ReadCertificates ( ) ;
38
- }
39
-
40
- return _certificates ;
41
- }
42
- }
43
-
44
- public EndpointDefaults EndpointDefaults
45
- {
46
- get
47
- {
48
- if ( _endpointDefaults == null )
49
- {
50
- ReadEndpointDefaults ( ) ;
51
- }
52
-
53
- return _endpointDefaults ;
54
- }
55
- }
56
-
57
- public IEnumerable < EndpointConfig > Endpoints
58
- {
59
- get
60
- {
61
- if ( _endpoints == null )
62
- {
63
- ReadEndpoints ( ) ;
64
- }
65
-
66
- return _endpoints ;
67
- }
68
- }
31
+ public IDictionary < string , CertificateConfig > Certificates { get ; }
32
+ public EndpointDefaults EndpointDefaults { get ; }
33
+ public IEnumerable < EndpointConfig > Endpoints { get ; }
34
+ public bool Latin1RequestHeaders { get ; }
69
35
70
- public bool Latin1RequestHeaders
36
+ private IDictionary < string , CertificateConfig > ReadCertificates ( )
71
37
{
72
- get
73
- {
74
- if ( _latin1RequestHeaders is null )
75
- {
76
- _latin1RequestHeaders = _configuration . GetValue < bool > ( Latin1RequestHeadersKey ) ;
77
- }
78
-
79
- return _latin1RequestHeaders . Value ;
80
- }
81
- }
82
-
83
- private void ReadCertificates ( )
84
- {
85
- _certificates = new Dictionary < string , CertificateConfig > ( 0 ) ;
38
+ var certificates = new Dictionary < string , CertificateConfig > ( 0 ) ;
86
39
87
40
var certificatesConfig = _configuration . GetSection ( CertificatesKey ) . GetChildren ( ) ;
88
41
foreach ( var certificateConfig in certificatesConfig )
89
42
{
90
- _certificates . Add ( certificateConfig . Key , new CertificateConfig ( certificateConfig ) ) ;
43
+ certificates . Add ( certificateConfig . Key , new CertificateConfig ( certificateConfig ) ) ;
91
44
}
45
+
46
+ return certificates ;
92
47
}
93
48
94
49
// "EndpointDefaults": {
95
50
// "Protocols": "Http1AndHttp2",
96
51
// }
97
- private void ReadEndpointDefaults ( )
52
+ private EndpointDefaults ReadEndpointDefaults ( )
98
53
{
99
54
var configSection = _configuration . GetSection ( EndpointDefaultsKey ) ;
100
- _endpointDefaults = new EndpointDefaults
55
+ return new EndpointDefaults
101
56
{
102
57
Protocols = ParseProtocols ( configSection [ ProtocolsKey ] )
103
58
} ;
104
59
}
105
60
106
- private void ReadEndpoints ( )
61
+ private IEnumerable < EndpointConfig > ReadEndpoints ( )
107
62
{
108
- _endpoints = new List < EndpointConfig > ( ) ;
63
+ var endpoints = new List < EndpointConfig > ( ) ;
109
64
110
65
var endpointsConfig = _configuration . GetSection ( EndpointsKey ) . GetChildren ( ) ;
111
66
foreach ( var endpointConfig in endpointsConfig )
@@ -133,8 +88,11 @@ private void ReadEndpoints()
133
88
ConfigSection = endpointConfig ,
134
89
Certificate = new CertificateConfig ( endpointConfig . GetSection ( CertificateKey ) ) ,
135
90
} ;
136
- _endpoints . Add ( endpoint ) ;
91
+
92
+ endpoints . Add ( endpoint ) ;
137
93
}
94
+
95
+ return endpoints ;
138
96
}
139
97
140
98
private static HttpProtocols ? ParseProtocols ( string protocols )
@@ -154,7 +112,6 @@ private void ReadEndpoints()
154
112
internal class EndpointDefaults
155
113
{
156
114
public HttpProtocols ? Protocols { get ; set ; }
157
- public IConfigurationSection ConfigSection { get ; set ; }
158
115
}
159
116
160
117
// "EndpointName": {
@@ -167,11 +124,41 @@ internal class EndpointDefaults
167
124
// }
168
125
internal class EndpointConfig
169
126
{
127
+ private IConfigurationSection _configSection ;
128
+ private ConfigSectionClone _configSectionClone ;
129
+
170
130
public string Name { get ; set ; }
171
131
public string Url { get ; set ; }
172
132
public HttpProtocols ? Protocols { get ; set ; }
173
- public IConfigurationSection ConfigSection { get ; set ; }
174
133
public CertificateConfig Certificate { get ; set ; }
134
+
135
+ // Compare config sections because it's accessible to app developers via an Action<EndpointConfiguration> callback.
136
+ // We cannot rely entirely on comparing config sections for equality, because KestrelConfigurationLoader.Reload() sets
137
+ // EndpointConfig properties to their default values. If a default value changes, the properties would no longer be equal,
138
+ // but the config sections could still be equal.
139
+ public IConfigurationSection ConfigSection
140
+ {
141
+ get => _configSection ;
142
+ set
143
+ {
144
+ _configSection = value ;
145
+ // The IConfigrationSection will mutate, so we need to take a snapshot to compare against later and check for changes.
146
+ _configSectionClone = new ConfigSectionClone ( value ) ;
147
+ }
148
+ }
149
+
150
+ public override bool Equals ( object obj ) =>
151
+ obj is EndpointConfig other &&
152
+ Name == other . Name &&
153
+ Url == other . Url &&
154
+ ( Protocols ?? ListenOptions . DefaultHttpProtocols ) == ( other . Protocols ?? ListenOptions . DefaultHttpProtocols ) &&
155
+ Certificate == other . Certificate &&
156
+ _configSectionClone == other . _configSectionClone ;
157
+
158
+ public override int GetHashCode ( ) => HashCode . Combine ( Name , Url , Protocols ?? ListenOptions . DefaultHttpProtocols , Certificate , _configSectionClone ) ;
159
+
160
+ public static bool operator == ( EndpointConfig lhs , EndpointConfig rhs ) => lhs is null ? rhs is null : lhs . Equals ( rhs ) ;
161
+ public static bool operator != ( EndpointConfig lhs , EndpointConfig rhs ) => ! ( lhs == rhs ) ;
175
162
}
176
163
177
164
// "CertificateName": {
@@ -206,5 +193,19 @@ public CertificateConfig(IConfigurationSection configSection)
206
193
public string Location { get ; set ; }
207
194
208
195
public bool ? AllowInvalid { get ; set ; }
196
+
197
+ public override bool Equals ( object obj ) =>
198
+ obj is CertificateConfig other &&
199
+ Path == other . Path &&
200
+ Password == other . Password &&
201
+ Subject == other . Subject &&
202
+ Store == other . Store &&
203
+ Location == other . Location &&
204
+ ( AllowInvalid ?? false ) == ( other . AllowInvalid ?? false ) ;
205
+
206
+ public override int GetHashCode ( ) => HashCode . Combine ( Path , Password , Subject , Store , Location , AllowInvalid ?? false ) ;
207
+
208
+ public static bool operator == ( CertificateConfig lhs , CertificateConfig rhs ) => lhs is null ? rhs is null : lhs . Equals ( rhs ) ;
209
+ public static bool operator != ( CertificateConfig lhs , CertificateConfig rhs ) => ! ( lhs == rhs ) ;
209
210
}
210
211
}
0 commit comments