11/*
2- * Copyright 2019, Optimizely
2+ * Copyright 2019-2020 , Optimizely
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -28,34 +28,64 @@ public class HttpProjectConfigManager : PollingProjectConfigManager
2828 {
2929 private string Url ;
3030 private string LastModifiedSince = string . Empty ;
31-
31+ private string DatafileAccessToken = string . Empty ;
3232 private HttpProjectConfigManager ( TimeSpan period , string url , TimeSpan blockingTimeout , bool autoUpdate , ILogger logger , IErrorHandler errorHandler )
3333 : base ( period , blockingTimeout , autoUpdate , logger , errorHandler )
3434 {
3535 Url = url ;
3636 }
3737
38+ private HttpProjectConfigManager ( TimeSpan period , string url , TimeSpan blockingTimeout , bool autoUpdate , ILogger logger , IErrorHandler errorHandler , string datafileAccessToken )
39+ : this ( period , url , blockingTimeout , autoUpdate , logger , errorHandler )
40+ {
41+ DatafileAccessToken = datafileAccessToken ;
42+ }
43+
3844 public Task OnReady ( )
3945 {
4046 return CompletableConfigManager . Task ;
4147 }
4248
4349#if ! NET40 && ! NET35
44- private static System . Net . Http . HttpClient Client ;
45- static HttpProjectConfigManager ( )
50+ // HttpClient wrapper class which can be used to mock HttpClient for unit testing.
51+ public class HttpClient
4652 {
47- Client = new System . Net . Http . HttpClient ( GetHttpClientHandler ( ) ) ;
48- }
53+ private System . Net . Http . HttpClient Client ;
4954
50- public static System . Net . Http . HttpClientHandler GetHttpClientHandler ( )
51- {
52- var handler = new System . Net . Http . HttpClientHandler ( ) {
53- AutomaticDecompression = System . Net . DecompressionMethods . GZip | System . Net . DecompressionMethods . Deflate
54- } ;
55+ public HttpClient ( )
56+ {
57+ Client = new System . Net . Http . HttpClient ( GetHttpClientHandler ( ) ) ;
58+ }
5559
56- return handler ;
60+ public HttpClient ( System . Net . Http . HttpClient httpClient ) : this ( )
61+ {
62+ if ( httpClient != null ) {
63+ Client = httpClient ;
64+ }
65+ }
66+
67+ public static System . Net . Http . HttpClientHandler GetHttpClientHandler ( )
68+ {
69+ var handler = new System . Net . Http . HttpClientHandler ( ) {
70+ AutomaticDecompression = System . Net . DecompressionMethods . GZip | System . Net . DecompressionMethods . Deflate
71+ } ;
72+
73+ return handler ;
74+ }
75+
76+ public virtual Task < System . Net . Http . HttpResponseMessage > SendAsync ( System . Net . Http . HttpRequestMessage httpRequestMessage )
77+ {
78+ return Client . SendAsync ( httpRequestMessage ) ;
79+ }
5780 }
5881
82+ private static HttpClient Client ;
83+
84+ static HttpProjectConfigManager ( )
85+ {
86+ Client = new HttpClient ( ) ;
87+ }
88+
5989 private string GetRemoteDatafileResponse ( )
6090 {
6191 var request = new System . Net . Http . HttpRequestMessage {
@@ -67,6 +97,10 @@ private string GetRemoteDatafileResponse()
6797 if ( ! string . IsNullOrEmpty ( LastModifiedSince ) )
6898 request . Headers . Add ( "If-Modified-Since" , LastModifiedSince ) ;
6999
100+ if ( ! string . IsNullOrEmpty ( DatafileAccessToken ) ) {
101+ request . Headers . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , DatafileAccessToken ) ;
102+ }
103+
70104 var httpResponse = Client . SendAsync ( request ) ;
71105 httpResponse . Wait ( ) ;
72106
@@ -136,11 +170,12 @@ public class Builder
136170 private readonly TimeSpan DEFAULT_PERIOD = TimeSpan . FromMinutes ( 5 ) ;
137171 private readonly TimeSpan DEFAULT_BLOCKINGOUT_PERIOD = TimeSpan . FromSeconds ( 15 ) ;
138172 private readonly string DEFAULT_FORMAT = "https://cdn.optimizely.com/datafiles/{0}.json" ;
139-
173+ private readonly string DEFAULT_AUTHENTICATED_DATAFILE_FORMAT = "https://config.optimizely.com/datafiles/auth/{0}.json" ;
140174 private string Datafile ;
175+ private string DatafileAccessToken ;
141176 private string SdkKey ;
142177 private string Url ;
143- private string Format ;
178+ private string Format ;
144179 private ILogger Logger ;
145180 private IErrorHandler ErrorHandler ;
146181 private TimeSpan Period ;
@@ -174,6 +209,14 @@ public Builder WithSdkKey(string sdkKey)
174209
175210 return this ;
176211 }
212+ #if ! NET40 && ! NET35
213+ public Builder WithAccessToken ( string accessToken )
214+ {
215+ this . DatafileAccessToken = accessToken ;
216+
217+ return this ;
218+ }
219+ #endif
177220
178221 public Builder WithUrl ( string url )
179222 {
@@ -260,15 +303,18 @@ public HttpProjectConfigManager Build(bool defer)
260303 ErrorHandler = new DefaultErrorHandler ( ) ;
261304
262305 if ( string . IsNullOrEmpty ( Format ) ) {
263- Format = DEFAULT_FORMAT ;
264- }
265306
266- if ( string . IsNullOrEmpty ( Url ) && string . IsNullOrEmpty ( SdkKey ) )
267- {
268- ErrorHandler . HandleError ( new Exception ( "SdkKey cannot be null" ) ) ;
307+ if ( string . IsNullOrEmpty ( DatafileAccessToken ) ) {
308+ Format = DEFAULT_FORMAT ;
309+ } else {
310+ Format = DEFAULT_AUTHENTICATED_DATAFILE_FORMAT ;
311+ }
269312 }
270- else if ( ! string . IsNullOrEmpty ( SdkKey ) )
271- {
313+
314+ if ( string . IsNullOrEmpty ( Url ) ) {
315+ if ( string . IsNullOrEmpty ( SdkKey ) ) {
316+ ErrorHandler . HandleError ( new Exception ( "SdkKey cannot be null" ) ) ;
317+ }
272318 Url = string . Format ( Format , SdkKey ) ;
273319 }
274320
@@ -290,7 +336,7 @@ public HttpProjectConfigManager Build(bool defer)
290336 }
291337
292338
293- configManager = new HttpProjectConfigManager ( Period , Url , BlockingTimeoutSpan , AutoUpdate , Logger , ErrorHandler ) ;
339+ configManager = new HttpProjectConfigManager ( Period , Url , BlockingTimeoutSpan , AutoUpdate , Logger , ErrorHandler , DatafileAccessToken ) ;
294340
295341 if ( Datafile != null )
296342 {
0 commit comments