11// Copyright (c) Just Eat, 2017. All rights reserved.
22// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.
33
4+ using System . Collections ;
5+ using System . Diagnostics . CodeAnalysis ;
46using System . Net ;
57
68namespace JustEat . HttpClientInterception ;
@@ -426,10 +428,7 @@ public HttpRequestInterceptionBuilder WithContentHeader(string name, IEnumerable
426428 throw new ArgumentNullException ( nameof ( values ) ) ;
427429 }
428430
429- if ( _contentHeaders is null )
430- {
431- _contentHeaders = new Dictionary < string , ICollection < string > > ( StringComparer . OrdinalIgnoreCase ) ;
432- }
431+ _contentHeaders ??= new Dictionary < string , ICollection < string > > ( StringComparer . OrdinalIgnoreCase ) ;
433432
434433 if ( ! _contentHeaders . TryGetValue ( name , out var current ) )
435434 {
@@ -551,10 +550,7 @@ public HttpRequestInterceptionBuilder WithResponseHeader(string name, IEnumerabl
551550 throw new ArgumentNullException ( nameof ( values ) ) ;
552551 }
553552
554- if ( _responseHeaders is null )
555- {
556- _responseHeaders = new Dictionary < string , ICollection < string > > ( StringComparer . OrdinalIgnoreCase ) ;
557- }
553+ _responseHeaders ??= new Dictionary < string , ICollection < string > > ( StringComparer . OrdinalIgnoreCase ) ;
558554
559555 if ( ! _responseHeaders . TryGetValue ( name , out ICollection < string > ? current ) )
560556 {
@@ -617,6 +613,29 @@ public HttpRequestInterceptionBuilder WithResponseHeaders(IDictionary<string, IC
617613 return this ;
618614 }
619615
616+ /// <summary>
617+ /// Sets a delegate to a method that generates any custom HTTP response headers to use.
618+ /// </summary>
619+ /// <param name="headerFactory">Any delegate that creates any custom HTTP response headers to use.</param>
620+ /// <returns>
621+ /// The current <see cref="HttpRequestInterceptionBuilder"/>.
622+ /// </returns>
623+ /// <exception cref="ArgumentNullException">
624+ /// <paramref name="headerFactory"/> is <see langword="null"/>.
625+ /// </exception>
626+ public HttpRequestInterceptionBuilder WithResponseHeaders (
627+ Func < IEnumerable < KeyValuePair < string , ICollection < string > > > > headerFactory )
628+ {
629+ if ( headerFactory is null )
630+ {
631+ throw new ArgumentNullException ( nameof ( headerFactory ) ) ;
632+ }
633+
634+ _responseHeaders = new DynamicDictionary ( headerFactory ) ;
635+ IncrementRevision ( ) ;
636+ return this ;
637+ }
638+
620639 /// <summary>
621640 /// Sets media type for the response body content.
622641 /// </summary>
@@ -869,10 +888,7 @@ public HttpRequestInterceptionBuilder ForRequestHeader(string name, IEnumerable<
869888 throw new ArgumentNullException ( nameof ( values ) ) ;
870889 }
871890
872- if ( _requestHeaders is null )
873- {
874- _requestHeaders = new Dictionary < string , ICollection < string > > ( StringComparer . OrdinalIgnoreCase ) ;
875- }
891+ _requestHeaders ??= new Dictionary < string , ICollection < string > > ( StringComparer . OrdinalIgnoreCase ) ;
876892
877893 if ( ! _requestHeaders . TryGetValue ( name , out ICollection < string > ? current ) )
878894 {
@@ -983,40 +999,61 @@ internal HttpInterceptionResponse Build()
983999 Version = _version ,
9841000 } ;
9851001
986- if ( _requestHeaders ? . Count > 0 )
1002+ if ( _requestHeaders is not null )
9871003 {
988- var headers = new Dictionary < string , IEnumerable < string > > ( _requestHeaders . Count ) ;
989-
990- foreach ( var pair in _requestHeaders )
1004+ if ( _requestHeaders is DynamicDictionary factory )
9911005 {
992- headers [ pair . Key ] = pair . Value ;
1006+ response . RequestHeaders = factory ;
9931007 }
1008+ else if ( _requestHeaders . Count > 0 )
1009+ {
1010+ var headers = new Dictionary < string , IEnumerable < string > > ( _requestHeaders . Count ) ;
9941011
995- response . RequestHeaders = headers ;
1012+ foreach ( var pair in _requestHeaders )
1013+ {
1014+ headers [ pair . Key ] = pair . Value ;
1015+ }
1016+
1017+ response . RequestHeaders = headers ;
1018+ }
9961019 }
9971020
998- if ( _responseHeaders ? . Count > 0 )
1021+ if ( _responseHeaders is not null )
9991022 {
1000- var headers = new Dictionary < string , IEnumerable < string > > ( _responseHeaders . Count ) ;
1001-
1002- foreach ( var pair in _responseHeaders )
1023+ if ( _responseHeaders is DynamicDictionary factory )
10031024 {
1004- headers [ pair . Key ] = pair . Value ;
1025+ response . ResponseHeaders = factory ;
10051026 }
1027+ else if ( _responseHeaders . Count > 0 )
1028+ {
1029+ var headers = new Dictionary < string , IEnumerable < string > > ( _responseHeaders . Count ) ;
10061030
1007- response . ResponseHeaders = headers ;
1031+ foreach ( var pair in _responseHeaders )
1032+ {
1033+ headers [ pair . Key ] = pair . Value ;
1034+ }
1035+
1036+ response . ResponseHeaders = headers ;
1037+ }
10081038 }
10091039
1010- if ( _contentHeaders ? . Count > 0 )
1040+ if ( _contentHeaders is not null )
10111041 {
1012- var headers = new Dictionary < string , IEnumerable < string > > ( _contentHeaders . Count ) ;
1013-
1014- foreach ( var pair in _contentHeaders )
1042+ if ( _contentHeaders is DynamicDictionary factory )
10151043 {
1016- headers [ pair . Key ] = pair . Value ;
1044+ response . ContentHeaders = factory ;
10171045 }
1046+ else if ( _contentHeaders . Count > 0 )
1047+ {
1048+ var headers = new Dictionary < string , IEnumerable < string > > ( _contentHeaders . Count ) ;
10181049
1019- response . ContentHeaders = headers ;
1050+ foreach ( var pair in _contentHeaders )
1051+ {
1052+ headers [ pair . Key ] = pair . Value ;
1053+ }
1054+
1055+ response . ContentHeaders = headers ;
1056+ }
10201057 }
10211058
10221059 return response ;
@@ -1036,4 +1073,105 @@ private void IncrementRevision()
10361073 _revision ++ ;
10371074 }
10381075 }
1076+
1077+ private sealed class DynamicDictionary :
1078+ IDictionary < string , ICollection < string > > ,
1079+ IEnumerable < KeyValuePair < string , IEnumerable < string > > >
1080+ {
1081+ private readonly Func < IEnumerable < KeyValuePair < string , ICollection < string > > > > _generator ;
1082+
1083+ internal DynamicDictionary ( Func < IEnumerable < KeyValuePair < string , ICollection < string > > > > generator )
1084+ {
1085+ _generator = generator ;
1086+ }
1087+
1088+ [ ExcludeFromCodeCoverage ]
1089+ public ICollection < string > Keys => throw new NotSupportedException ( ) ;
1090+
1091+ [ ExcludeFromCodeCoverage ]
1092+ public ICollection < ICollection < string > > Values => throw new NotSupportedException ( ) ;
1093+
1094+ [ ExcludeFromCodeCoverage ]
1095+ public int Count => throw new NotSupportedException ( ) ;
1096+
1097+ [ ExcludeFromCodeCoverage ]
1098+ public bool IsReadOnly => true ;
1099+
1100+ [ ExcludeFromCodeCoverage ]
1101+ public ICollection < string > this [ string key ]
1102+ {
1103+ get => throw new NotSupportedException ( ) ;
1104+ set => throw new NotSupportedException ( ) ;
1105+ }
1106+
1107+ public IEnumerator < KeyValuePair < string , ICollection < string > > > GetEnumerator ( )
1108+ => _generator ( ) . GetEnumerator ( ) ;
1109+
1110+ IEnumerator IEnumerable . GetEnumerator ( )
1111+ => GetEnumerator ( ) ;
1112+
1113+ IEnumerator < KeyValuePair < string , IEnumerable < string > > > IEnumerable < KeyValuePair < string , IEnumerable < string > > > . GetEnumerator ( )
1114+ => new EnumeratorAdapter ( GetEnumerator ( ) ) ;
1115+
1116+ [ ExcludeFromCodeCoverage ]
1117+ public void Add ( string key , ICollection < string > value )
1118+ => throw new NotSupportedException ( ) ;
1119+
1120+ [ ExcludeFromCodeCoverage ]
1121+ public void Add ( KeyValuePair < string , ICollection < string > > item )
1122+ => throw new NotSupportedException ( ) ;
1123+
1124+ [ ExcludeFromCodeCoverage ]
1125+ public void Clear ( )
1126+ => throw new NotSupportedException ( ) ;
1127+
1128+ [ ExcludeFromCodeCoverage ]
1129+ public bool Contains ( KeyValuePair < string , ICollection < string > > item )
1130+ => throw new NotSupportedException ( ) ;
1131+
1132+ [ ExcludeFromCodeCoverage ]
1133+ public bool ContainsKey ( string key )
1134+ => throw new NotSupportedException ( ) ;
1135+
1136+ [ ExcludeFromCodeCoverage ]
1137+ public void CopyTo ( KeyValuePair < string , ICollection < string > > [ ] array , int arrayIndex )
1138+ => throw new NotSupportedException ( ) ;
1139+
1140+ [ ExcludeFromCodeCoverage ]
1141+ public bool Remove ( string key )
1142+ => throw new NotSupportedException ( ) ;
1143+
1144+ [ ExcludeFromCodeCoverage ]
1145+ public bool Remove ( KeyValuePair < string , ICollection < string > > item )
1146+ => throw new NotSupportedException ( ) ;
1147+
1148+ [ ExcludeFromCodeCoverage ]
1149+ public bool TryGetValue ( string key , out ICollection < string > value )
1150+ => throw new NotSupportedException ( ) ;
1151+
1152+ private sealed class EnumeratorAdapter : IEnumerator < KeyValuePair < string , IEnumerable < string > > >
1153+ {
1154+ private readonly IEnumerator < KeyValuePair < string , ICollection < string > > > _enumerator ;
1155+
1156+ internal EnumeratorAdapter ( IEnumerator < KeyValuePair < string , ICollection < string > > > enumerator )
1157+ {
1158+ _enumerator = enumerator ;
1159+ }
1160+
1161+ public KeyValuePair < string , IEnumerable < string > > Current
1162+ => new ( _enumerator . Current . Key , _enumerator . Current . Value ) ;
1163+
1164+ object IEnumerator . Current
1165+ => _enumerator . Current ;
1166+
1167+ public void Dispose ( )
1168+ => _enumerator . Dispose ( ) ;
1169+
1170+ public bool MoveNext ( )
1171+ => _enumerator . MoveNext ( ) ;
1172+
1173+ public void Reset ( )
1174+ => _enumerator . Reset ( ) ;
1175+ }
1176+ }
10391177}
0 commit comments