using System.IO;
using System.Net.Cache;
using System.Net.Http;
+using System.Net.Http.Headers;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.Serialization;
get; set;
}
- public static new RequestCachePolicy? DefaultCachePolicy { get; set; } = new RequestCachePolicy(RequestCacheLevel.BypassCache);
+ private static RequestCachePolicy? _defaultCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
+ private static bool _isDefaultCachePolicySet;
+
+ public static new RequestCachePolicy? DefaultCachePolicy
+ {
+ get
+ {
+ return _defaultCachePolicy;
+ }
+ set
+ {
+ _isDefaultCachePolicySet = true;
+ _defaultCachePolicy = value;
+ }
+ }
public DateTime IfModifiedSince
{
request.Headers.Host = Host;
}
+ AddCacheControlHeaders(request);
+
// Copy the HttpWebRequest request headers from the WebHeaderCollection into HttpRequestMessage.Headers and
// HttpRequestMessage.Content.Headers.
foreach (string headerName in _webHeaderCollection)
}
}
+ private void AddCacheControlHeaders(HttpRequestMessage request)
+ {
+ RequestCachePolicy? policy = GetApplicableCachePolicy();
+
+ if (policy != null && policy.Level != RequestCacheLevel.BypassCache)
+ {
+ CacheControlHeaderValue? cacheControl = null;
+ HttpHeaderValueCollection<NameValueHeaderValue> pragmaHeaders = request.Headers.Pragma;
+
+ if (policy is HttpRequestCachePolicy httpRequestCachePolicy)
+ {
+ switch (httpRequestCachePolicy.Level)
+ {
+ case HttpRequestCacheLevel.NoCacheNoStore:
+ cacheControl = new CacheControlHeaderValue
+ {
+ NoCache = true,
+ NoStore = true
+ };
+ pragmaHeaders.Add(new NameValueHeaderValue("no-cache"));
+ break;
+ case HttpRequestCacheLevel.Reload:
+ cacheControl = new CacheControlHeaderValue
+ {
+ NoCache = true
+ };
+ pragmaHeaders.Add(new NameValueHeaderValue("no-cache"));
+ break;
+ case HttpRequestCacheLevel.CacheOnly:
+ throw new WebException(SR.CacheEntryNotFound, WebExceptionStatus.CacheEntryNotFound);
+ case HttpRequestCacheLevel.CacheOrNextCacheOnly:
+ cacheControl = new CacheControlHeaderValue
+ {
+ OnlyIfCached = true
+ };
+ break;
+ case HttpRequestCacheLevel.Default:
+ cacheControl = new CacheControlHeaderValue();
+
+ if (httpRequestCachePolicy.MinFresh > TimeSpan.Zero)
+ {
+ cacheControl.MinFresh = httpRequestCachePolicy.MinFresh;
+ }
+
+ if (httpRequestCachePolicy.MaxAge != TimeSpan.MaxValue)
+ {
+ cacheControl.MaxAge = httpRequestCachePolicy.MaxAge;
+ }
+
+ if (httpRequestCachePolicy.MaxStale > TimeSpan.Zero)
+ {
+ cacheControl.MaxStale = true;
+ cacheControl.MaxStaleLimit = httpRequestCachePolicy.MaxStale;
+ }
+
+ break;
+ case HttpRequestCacheLevel.Refresh:
+ cacheControl = new CacheControlHeaderValue
+ {
+ MaxAge = TimeSpan.Zero
+ };
+ pragmaHeaders.Add(new NameValueHeaderValue("no-cache"));
+ break;
+ }
+ }
+ else
+ {
+ switch (policy.Level)
+ {
+ case RequestCacheLevel.NoCacheNoStore:
+ cacheControl = new CacheControlHeaderValue
+ {
+ NoCache = true,
+ NoStore = true
+ };
+ pragmaHeaders.Add(new NameValueHeaderValue("no-cache"));
+ break;
+ case RequestCacheLevel.Reload:
+ cacheControl = new CacheControlHeaderValue
+ {
+ NoCache = true
+ };
+ pragmaHeaders.Add(new NameValueHeaderValue("no-cache"));
+ break;
+ case RequestCacheLevel.CacheOnly:
+ throw new WebException(SR.CacheEntryNotFound, WebExceptionStatus.CacheEntryNotFound);
+ }
+ }
+
+ if (cacheControl != null)
+ {
+ request.Headers.CacheControl = cacheControl;
+ }
+ }
+ }
+
+ private RequestCachePolicy? GetApplicableCachePolicy()
+ {
+ if (CachePolicy != null)
+ {
+ return CachePolicy;
+ }
+ else if (_isDefaultCachePolicySet && DefaultCachePolicy != null)
+ {
+ return DefaultCachePolicy;
+ }
+ else
+ {
+ return WebRequest.DefaultCachePolicy;
+ }
+ }
+
public override IAsyncResult BeginGetResponse(AsyncCallback? callback, object? state)
{
CheckAbort();
request.Abort();
}
+ [Theory]
+ [InlineData(HttpRequestCacheLevel.NoCacheNoStore, null, null, new string[] { "Pragma: no-cache", "Cache-Control: no-store, no-cache"})]
+ [InlineData(HttpRequestCacheLevel.Reload, null, null, new string[] { "Pragma: no-cache", "Cache-Control: no-cache" })]
+ [InlineData(HttpRequestCacheLevel.CacheOrNextCacheOnly, null, null, new string[] { "Cache-Control: only-if-cached" })]
+ [InlineData(HttpRequestCacheLevel.Default, HttpCacheAgeControl.MinFresh, 10, new string[] { "Cache-Control: min-fresh=10" })]
+ [InlineData(HttpRequestCacheLevel.Default, HttpCacheAgeControl.MaxAge, 10, new string[] { "Cache-Control: max-age=10" })]
+ [InlineData(HttpRequestCacheLevel.Default, HttpCacheAgeControl.MaxStale, 10, new string[] { "Cache-Control: max-stale=10" })]
+ [InlineData(HttpRequestCacheLevel.Refresh, null, null, new string[] { "Pragma: no-cache", "Cache-Control: max-age=0" })]
+ public async Task SendHttpGetRequest_WithHttpCachePolicy_AddCacheHeaders(
+ HttpRequestCacheLevel requestCacheLevel, HttpCacheAgeControl? ageControl, int? age, string[] expectedHeaders)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ HttpWebRequest request = WebRequest.CreateHttp(uri);
+ request.CachePolicy = ageControl != null ?
+ new HttpRequestCachePolicy(ageControl.Value, TimeSpan.FromSeconds((double)age))
+ : new HttpRequestCachePolicy(requestCacheLevel);
+ Task<WebResponse> getResponse = GetResponseAsync(request);
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+
+ foreach (string header in expectedHeaders)
+ {
+ Assert.Contains(header, headers);
+ }
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }
+
+ [Theory]
+ [InlineData(RequestCacheLevel.NoCacheNoStore, new string[] { "Pragma: no-cache", "Cache-Control: no-store, no-cache" })]
+ [InlineData(RequestCacheLevel.Reload, new string[] { "Pragma: no-cache", "Cache-Control: no-cache" })]
+ public async Task SendHttpGetRequest_WithCachePolicy_AddCacheHeaders(
+ RequestCacheLevel requestCacheLevel, string[] expectedHeaders)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ HttpWebRequest request = WebRequest.CreateHttp(uri);
+ request.CachePolicy = new RequestCachePolicy(requestCacheLevel);
+ Task<WebResponse> getResponse = GetResponseAsync(request);
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+
+ foreach (string header in expectedHeaders)
+ {
+ Assert.Contains(header, headers);
+ }
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }
+
+ [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ [InlineData(RequestCacheLevel.NoCacheNoStore, new string[] { "Pragma: no-cache", "Cache-Control: no-store, no-cache" })]
+ [InlineData(RequestCacheLevel.Reload, new string[] { "Pragma: no-cache", "Cache-Control: no-cache" })]
+ public void SendHttpGetRequest_WithGlobalCachePolicy_AddCacheHeaders(
+ RequestCacheLevel requestCacheLevel, string[] expectedHeaders)
+ {
+ RemoteExecutor.Invoke(async (async, reqCacheLevel, eh0, eh1) =>
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ HttpWebRequest.DefaultCachePolicy = new RequestCachePolicy(Enum.Parse<RequestCacheLevel>(reqCacheLevel));
+ HttpWebRequest request = WebRequest.CreateHttp(uri);
+ Task<WebResponse> getResponse = bool.Parse(async) ? request.GetResponseAsync() : Task.Run(() => request.GetResponse());
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+ Assert.Contains(eh0, headers);
+ Assert.Contains(eh1, headers);
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }, (this is HttpWebRequestTest_Async).ToString(), requestCacheLevel.ToString(), expectedHeaders[0], expectedHeaders[1]).Dispose();
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task SendHttpGetRequest_WithCachePolicyCacheOnly_ThrowException(
+ bool isHttpCachePolicy)
+ {
+ HttpWebRequest request = WebRequest.CreateHttp("http://anything");
+ request.CachePolicy = isHttpCachePolicy ? new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheOnly)
+ : new RequestCachePolicy(RequestCacheLevel.CacheOnly);
+ WebException exception = await Assert.ThrowsAsync<WebException>(() => GetResponseAsync(request));
+ Assert.Equal(SR.CacheEntryNotFound, exception.Message);
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void SendHttpGetRequest_WithGlobalCachePolicyBypassCache_DoNotAddCacheHeaders()
+ {
+ RemoteExecutor.Invoke(async () =>
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ HttpWebRequest.DefaultCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
+ HttpWebRequest request = WebRequest.CreateHttp(uri);
+ Task<WebResponse> getResponse = request.GetResponseAsync();
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+
+ foreach (string header in headers)
+ {
+ Assert.DoesNotContain("Pragma", header);
+ Assert.DoesNotContain("Cache-Control", header);
+ }
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }).Dispose();
+ }
+
+ [Fact]
+ public async Task SendHttpGetRequest_WithCachePolicyBypassCache_DoNotAddHeaders()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ HttpWebRequest request = WebRequest.CreateHttp(uri);
+ request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
+ Task<WebResponse> getResponse = request.GetResponseAsync();
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+
+ foreach (string header in headers)
+ {
+ Assert.DoesNotContain("Pragma", header);
+ Assert.DoesNotContain("Cache-Control", header);
+ }
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }
+
private void RequestStreamCallback(IAsyncResult asynchronousResult)
{
RequestState state = (RequestState)asynchronousResult.AsyncState;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
+using System.Net.Cache;
+using System.Net.Test.Common;
+using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
Assert.False(success);
}
+ [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ [InlineData(RequestCacheLevel.NoCacheNoStore, new string[] { "Pragma: no-cache", "Cache-Control: no-store, no-cache" })]
+ [InlineData(RequestCacheLevel.Reload, new string[] { "Pragma: no-cache", "Cache-Control: no-cache" })]
+ public void SendGetRequest_WithGlobalCachePolicy_AddCacheHeaders(
+ RequestCacheLevel requestCacheLevel, string[] expectedHeaders)
+ {
+ RemoteExecutor.Invoke(async (reqCacheLevel, eh0, eh1) =>
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ WebRequest.DefaultCachePolicy = new RequestCachePolicy(Enum.Parse<RequestCacheLevel>(reqCacheLevel));
+ WebRequest request = WebRequest.Create(uri);
+ Task<WebResponse> getResponse = request.GetResponseAsync();
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+ Assert.Contains(eh0, headers);
+ Assert.Contains(eh1, headers);
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }, requestCacheLevel.ToString(), expectedHeaders[0], expectedHeaders[1]).Dispose();
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void SendGetRequest_WithGlobalCachePolicyBypassCache_DoNotAddCacheHeaders()
+ {
+ RemoteExecutor.Invoke(async () =>
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ WebRequest.DefaultCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
+ WebRequest request = WebRequest.Create(uri);
+ Task<WebResponse> getResponse = request.GetResponseAsync();
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+
+ foreach(string header in headers)
+ {
+ Assert.DoesNotContain("Pragma", header);
+ Assert.DoesNotContain("Cache-Control", header);
+ }
+ });
+
+ using (var response = (HttpWebResponse)await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }).Dispose();
+ }
+
private class FakeRequest : WebRequest
{
private readonly Uri _uri;