Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,180 @@
//------------------------------------------------------------------------------
// <copyright file="GenericUriParser.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*++
Abstract:
This is a public sealed class that exposes various Uri parsing options
suported by built in Uri parser
Author:
Alexei Vopilov Jul 26 2004
Revision History:
--*/
namespace System {
using System.Globalization;
using System.Collections;
using System.Security.Permissions;
//
// This enum specifies the public options used to customize a hierarchical built-in parser.
//
[Flags]
public enum GenericUriParserOptions
{
// A hierarchical URI, allows a userinfo, non empty Inet-based authority, path, query and fragment
// The URI path gets agressively compressed means dots, slashes and backslashes are unescaped,
// backslashesare converted, and then it compresses the path. It also removes trailing dots,
// empty segments and dots-only segments
Default = 0x0,
// Allows a free style authority that would terminate with '/'
GenericAuthority = 0x1,
// Allows an empty authority foo:///
AllowEmptyAuthority = 0x2,
// Disables a user info component, it implied in the case of GenericAuthority flag
NoUserInfo = 0x4,
// Disables a port component, it is implied in the case of GenericAuthority flag
NoPort = 0x8,
// Disables a query. A ? char is considered as part of the path and is escaped
NoQuery = 0x10,
// Disables a fragment. A # char is considered as part of the path or query and is escaped
NoFragment = 0x20,
// if false then converta \ to /, otheriwse does this conversion for the Path component.
DontConvertPathBackslashes = 0x40,
// if false, then a/./b or a/.../b becomes a/b and /a/../b becomes /b
DontCompressPath = 0x80,
// if false then a/%2e./b becomes a/../b and then usually compressed
DontUnescapePathDotsAndSlashes= 0x100,
// IDN hosts supported. if true then unicode hostname is converted to IDN host
// and vice versa
Idn = 0x200,
// Iri strict parsing flag. Makes sense for Unicode. If true then string is
// normalized, bidi control characters are removed, unicode char limits are checked
IriParsing = 0x400
}
//
// A hierachical Uri parser that supports various customization options
//
// ATTN: This type must be compile-time registered with UriParser.CheckSetIsSimpleFlag() method
// to avoid calling into the user code if there is no one.
//
public class GenericUriParser: UriParser
{
//
// The only availabe .ctor.
//
public GenericUriParser(GenericUriParserOptions options)
: base(MapGenericParserOptions(options))
{
}
//
private static UriSyntaxFlags MapGenericParserOptions(GenericUriParserOptions options)
{
//
// Here we map public flags to internal ones
// Note an instacne of this parser is always a "simple parser" since the class is sealed.
//
UriSyntaxFlags flags = DefaultGenericUriParserFlags;
if ((options & GenericUriParserOptions.GenericAuthority) != 0)
{
// Disable some options that are not compatible with generic authority
flags &= ~(UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost);
flags |= UriSyntaxFlags.AllowAnyOtherHost;
}
if ((options & GenericUriParserOptions.AllowEmptyAuthority) != 0)
{
flags |= UriSyntaxFlags.AllowEmptyHost;
}
if ((options & GenericUriParserOptions.NoUserInfo) != 0)
{
flags &= ~UriSyntaxFlags.MayHaveUserInfo;
}
if ((options & GenericUriParserOptions.NoPort) != 0)
{
flags &= ~UriSyntaxFlags.MayHavePort;
}
if ((options & GenericUriParserOptions.NoQuery) != 0)
{
flags &= ~UriSyntaxFlags.MayHaveQuery;
}
if ((options & GenericUriParserOptions.NoFragment) != 0)
{
flags &= ~UriSyntaxFlags.MayHaveFragment;
}
if ((options & GenericUriParserOptions.DontConvertPathBackslashes) != 0)
{
flags &= ~UriSyntaxFlags.ConvertPathSlashes;
}
if ((options & GenericUriParserOptions.DontCompressPath) != 0)
{
flags &= ~(UriSyntaxFlags.CompressPath | UriSyntaxFlags.CanonicalizeAsFilePath);
}
if ((options & GenericUriParserOptions.DontUnescapePathDotsAndSlashes) != 0)
{
flags &= ~UriSyntaxFlags.UnEscapeDotsAndSlashes;
}
if ((options & GenericUriParserOptions.Idn) != 0)
{
flags |= UriSyntaxFlags.AllowIdn;
}
if ((options & GenericUriParserOptions.IriParsing) != 0)
{
flags |= UriSyntaxFlags.AllowIriParsing;
}
return flags;
}
private const UriSyntaxFlags DefaultGenericUriParserFlags =
UriSyntaxFlags.MustHaveAuthority |
//
UriSyntaxFlags.MayHaveUserInfo |
UriSyntaxFlags.MayHavePort |
UriSyntaxFlags.MayHavePath |
UriSyntaxFlags.MayHaveQuery |
UriSyntaxFlags.MayHaveFragment |
//
UriSyntaxFlags.AllowUncHost | //
UriSyntaxFlags.AllowAnInternetHost |
//
UriSyntaxFlags.PathIsRooted |
//
UriSyntaxFlags.ConvertPathSlashes |
UriSyntaxFlags.CompressPath |
UriSyntaxFlags.CanonicalizeAsFilePath |
UriSyntaxFlags.UnEscapeDotsAndSlashes;
}
}

View File

@@ -0,0 +1,370 @@
namespace System
{
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
internal static class IriHelper
{
//
// Checks if provided non surrogate char lies in iri range
//
internal static bool CheckIriUnicodeRange(char unicode, bool isQuery)
{
return ((unicode >= '\u00A0' && unicode <= '\uD7FF') ||
(unicode >= '\uF900' && unicode <= '\uFDCF') ||
(unicode >= '\uFDF0' && unicode <= '\uFFEF') ||
(isQuery && unicode >= '\uE000' && unicode <= '\uF8FF'));
}
//
// Check if highSurr and lowSurr are a surrogate pair then
// it checks if the combined char is in the range
// Takes in isQuery because because iri restrictions for query are different
//
internal static bool CheckIriUnicodeRange(char highSurr, char lowSurr, ref bool surrogatePair, bool isQuery)
{
bool inRange = false;
surrogatePair = false;
Debug.Assert(Char.IsHighSurrogate(highSurr));
if (Char.IsSurrogatePair(highSurr, lowSurr))
{
surrogatePair = true;
char[] chars = new char[2] { highSurr, lowSurr };
string surrPair = new string(chars);
if (((string.CompareOrdinal(surrPair, "\U00010000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0001FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00020000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0002FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00030000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0003FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00040000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0004FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00050000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0005FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00060000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0006FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00070000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0007FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00080000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0008FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00090000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0009FFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U000A0000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U000AFFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U000B0000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U000BFFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U000C0000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U000CFFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U000D0000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U000DFFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U000E1000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U000EFFFD") <= 0)) ||
(isQuery &&
(((string.CompareOrdinal(surrPair, "\U000F0000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U000FFFFD") <= 0)) ||
((string.CompareOrdinal(surrPair, "\U00100000") >= 0)
&& (string.CompareOrdinal(surrPair, "\U0010FFFD") <= 0)))))
{
inRange = true;
}
}
return inRange;
}
//
// Check reserved chars according to rfc 3987 in a sepecific component
//
internal static bool CheckIsReserved(char ch, UriComponents component)
{
if ((component != UriComponents.Scheme) &&
(component != UriComponents.UserInfo) &&
(component != UriComponents.Host) &&
(component != UriComponents.Port) &&
(component != UriComponents.Path) &&
(component != UriComponents.Query) &&
(component != UriComponents.Fragment)
)
{
return (component == (UriComponents)0) ? Uri.IsGenDelim(ch) : false;
}
else
{
switch (component)
{
// Reserved chars according to rfc 3987
case UriComponents.UserInfo:
if (ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']' || ch == '@')
return true;
break;
case UriComponents.Host:
if (ch == ':' || ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']' || ch == '@')
return true;
break;
case UriComponents.Path:
if (ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']')
return true;
break;
case UriComponents.Query:
if (ch == '#' || ch == '[' || ch == ']')
return true;
break;
case UriComponents.Fragment:
if (ch == '#' || ch == '[' || ch == ']')
return true;
break;
default:
break;
}
return false;
}
}
//
// IRI normalization for strings containing characters that are not allowed or
// escaped characters that should be unescaped in the context of the specified Uri component.
//
internal static unsafe string EscapeUnescapeIri(char* pInput, int start, int end, UriComponents component)
{
char[] dest = new char[end - start];
byte[] bytes = null;
// Pin the array to do pointer accesses
GCHandle destHandle = GCHandle.Alloc(dest, GCHandleType.Pinned);
char* pDest = (char*)destHandle.AddrOfPinnedObject();
const int percentEncodingLen = 3; // Escaped UTF-8 will take 3 chars: %AB.
const int bufferCapacityIncrease = 30 * percentEncodingLen;
int bufferRemaining = 0;
int next = start;
int destOffset = 0;
char ch;
bool escape = false;
bool surrogatePair = false;
for (; next < end; ++next)
{
escape = false;
surrogatePair = false;
if ((ch = pInput[next]) == '%')
{
if (next + 2 < end)
{
ch = UriHelper.EscapedAscii(pInput[next + 1], pInput[next + 2]);
// Do not unescape a reserved char
if (ch == Uri.c_DummyChar || ch == '%' || CheckIsReserved(ch, component) || UriHelper.IsNotSafeForUnescape(ch))
{
// keep as is
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next++];
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next++];
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next];
continue;
}
else if (ch <= '\x7F')
{
Debug.Assert(ch < 0xFF, "Expecting ASCII character.");
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
//ASCII
pDest[destOffset++] = ch;
next += 2;
continue;
}
else
{
// possibly utf8 encoded sequence of unicode
// check if safe to unescape according to Iri rules
Debug.Assert(ch < 0xFF, "Expecting ASCII character.");
int startSeq = next;
int byteCount = 1;
// lazy initialization of max size, will reuse the array for next sequences
if ((object)bytes == null)
bytes = new byte[end - next];
bytes[0] = (byte)ch;
next += 3;
while (next < end)
{
// Check on exit criterion
if ((ch = pInput[next]) != '%' || next + 2 >= end)
break;
// already made sure we have 3 characters in str
ch = UriHelper.EscapedAscii(pInput[next + 1], pInput[next + 2]);
//invalid hex sequence ?
if (ch == Uri.c_DummyChar)
break;
// character is not part of a UTF-8 sequence ?
else if (ch < '\x80')
break;
else
{
//a UTF-8 sequence
bytes[byteCount++] = (byte)ch;
next += 3;
}
Debug.Assert(ch < 0xFF, "Expecting ASCII character.");
}
next--; // for loop will increment
// Using encoder with no replacement fall-back will skip all invalid UTF-8 sequences.
Encoding noFallbackCharUTF8 = (Encoding)Encoding.UTF8.Clone();
noFallbackCharUTF8.EncoderFallback = new EncoderReplacementFallback("");
noFallbackCharUTF8.DecoderFallback = new DecoderReplacementFallback("");
char[] unescapedChars = new char[bytes.Length];
int charCount = noFallbackCharUTF8.GetChars(bytes, 0, byteCount, unescapedChars, 0);
if (charCount != 0)
{
// If invalid sequences were present in the original escaped string, we need to
// copy the escaped versions of those sequences.
// Decoded Unicode values will be kept only when they are allowed by the URI/IRI RFC
// rules.
UriHelper.MatchUTF8Sequence(pDest, dest, ref destOffset, unescapedChars, charCount, bytes,
byteCount, component == UriComponents.Query, true);
}
else
{
// copy escaped sequence as is
for (int i = startSeq; i <= next; ++i)
{
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[i];
}
}
}
}
else
{
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next];
}
}
else if (ch > '\x7f')
{
// unicode
char ch2;
if ((Char.IsHighSurrogate(ch)) && (next + 1 < end))
{
ch2 = pInput[next + 1];
escape = !CheckIriUnicodeRange(ch, ch2, ref surrogatePair, component == UriComponents.Query);
if (!escape)
{
// copy the two chars
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next++];
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next];
}
}
else
{
if (CheckIriUnicodeRange(ch, component == UriComponents.Query))
{
if (!Uri.IsBidiControlCharacter(ch))
{
// copy it
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next];
}
}
else
{
// escape it
escape = true;
}
}
}
else
{
// just copy the character
Debug.Assert(dest.Length > destOffset, "Buffer overrun detected");
pDest[destOffset++] = pInput[next];
}
if (escape)
{
const int maxNumberOfBytesEncoded = 4;
if (bufferRemaining < maxNumberOfBytesEncoded * percentEncodingLen)
{
int newBufferLength = 0;
checked
{
// may need more memory since we didn't anticipate escaping
newBufferLength = dest.Length + bufferCapacityIncrease;
bufferRemaining += bufferCapacityIncrease;
}
char[] newDest = new char[newBufferLength];
fixed (char* pNewDest = newDest)
{
#if !UT_PUBLIC_DEPENDS
Buffer.Memcpy((byte*)pNewDest, (byte*)pDest, destOffset * sizeof(char));
#else
for (int idx=0; idx<destOffset; idx++)
{
pNewDest[idx] = pDest[idx];
}
#endif
}
if (destHandle.IsAllocated)
{
destHandle.Free();
}
dest = newDest;
// re-pin new dest[] array
destHandle = GCHandle.Alloc(dest, GCHandleType.Pinned);
pDest = (char*)destHandle.AddrOfPinnedObject();
}
byte[] encodedBytes = new byte[maxNumberOfBytesEncoded];
fixed (byte* pEncodedBytes = encodedBytes)
{
int encodedBytesCount = Encoding.UTF8.GetBytes(pInput + next, surrogatePair ? 2 : 1, pEncodedBytes, maxNumberOfBytesEncoded);
Debug.Assert(encodedBytesCount <= maxNumberOfBytesEncoded, "UTF8 encoder should not exceed specified byteCount");
bufferRemaining -= encodedBytesCount * percentEncodingLen;
for (int count = 0; count < encodedBytesCount; ++count)
{
UriHelper.EscapeAsciiChar((char)encodedBytes[count], dest, ref destOffset);
}
}
}
}
if (destHandle.IsAllocated)
destHandle.Free();
Debug.Assert(destOffset <= dest.Length, "Buffer overrun detected");
return new string(dest, 0, destOffset);
}
}
}

View File

@@ -0,0 +1,427 @@
//------------------------------------------------------------------------------
// <copyright file="AuthenticationManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Net {
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Globalization;
using System.Net.Configuration;
using System.Reflection;
using System.Security.Authentication.ExtendedProtection;
using System.Security.Permissions;
using System;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
//
// A contract that applications can use to restrict auth scenarios in current appDomain
//
public interface ICredentialPolicy
{
bool ShouldSendCredential(
Uri challengeUri,
WebRequest request,
NetworkCredential credential,
IAuthenticationModule authenticationModule);
}
/// <devdoc>
/// <para>Manages the authentication modules called during the client authentication
/// process.</para>
/// </devdoc>
public class AuthenticationManager
{
private static object instanceLock = new object();
private static IAuthenticationManager internalInstance = null;
internal const string authenticationManagerRoot = "System.Net.AuthenticationManager";
// Following names are used both as a per-app key as a global setting
internal const string configHighPerformance = authenticationManagerRoot + ".HighPerformance";
internal const string configPrefixLookupMaxCount = authenticationManagerRoot + ".PrefixLookupMaxCount";
private AuthenticationManager()
{
}
private static IAuthenticationManager Instance
{
get
{
if (internalInstance == null)
{
lock (instanceLock)
{
if (internalInstance == null)
{
internalInstance = SelectAuthenticationManagerInstance();
}
}
}
return internalInstance;
}
}
private static IAuthenticationManager SelectAuthenticationManagerInstance()
{
bool highPerformance = false;
try
{
if (RegistryConfiguration.GlobalConfigReadInt(configHighPerformance, 0) == 1)
{
highPerformance = true;
}
else if (RegistryConfiguration.AppConfigReadInt(configHighPerformance, 0) == 1)
{
highPerformance = true;
}
if (highPerformance)
{
int? maxPrefixLookupEntries = ReadPrefixLookupMaxEntriesConfig();
if ((maxPrefixLookupEntries != null) && (maxPrefixLookupEntries > 0))
{
return new AuthenticationManager2((int)maxPrefixLookupEntries);
}
else
{
return new AuthenticationManager2();
}
}
}
catch (Exception e)
{
if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
{
throw;
}
}
return new AuthenticationManagerDefault();
}
private static int? ReadPrefixLookupMaxEntriesConfig()
{
int? maxPrefixLookupEntries = null;
int configuredMaxPrefixLookupEntries =
RegistryConfiguration.GlobalConfigReadInt(configPrefixLookupMaxCount, -1);
if (configuredMaxPrefixLookupEntries > 0)
{
maxPrefixLookupEntries = configuredMaxPrefixLookupEntries;
}
// Per-process setting will override global configuration.
configuredMaxPrefixLookupEntries =
RegistryConfiguration.AppConfigReadInt(configPrefixLookupMaxCount, -1);
if (configuredMaxPrefixLookupEntries > 0)
{
maxPrefixLookupEntries = configuredMaxPrefixLookupEntries;
}
return maxPrefixLookupEntries;
}
public static ICredentialPolicy CredentialPolicy {
get
{
return Instance.CredentialPolicy;
}
set
{
#if FEATURE_MONO_CAS
ExceptionHelper.ControlPolicyPermission.Demand();
#endif
Instance.CredentialPolicy = value;
}
}
public static StringDictionary CustomTargetNameDictionary
{
get
{
return Instance.CustomTargetNameDictionary;
}
}
internal static SpnDictionary SpnDictionary
{
get
{
return Instance.SpnDictionary;
}
}
internal static void EnsureConfigLoaded()
{
Instance.EnsureConfigLoaded();
}
internal static bool OSSupportsExtendedProtection
{
get
{
return Instance.OSSupportsExtendedProtection;
}
}
internal static bool SspSupportsExtendedProtection
{
get
{
return Instance.SspSupportsExtendedProtection;
}
}
/// <devdoc>
/// <para>Call each registered authentication module to determine the first module that
/// can respond to the authentication request.</para>
/// </devdoc>
public static Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
{
return Instance.Authenticate(challenge, request, credentials);
}
/// <devdoc>
/// <para>Pre-authenticates a request.</para>
/// </devdoc>
public static Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
{
return Instance.PreAuthenticate(request, credentials);
}
/// <devdoc>
/// <para>Registers an authentication module with the authentication manager.</para>
/// </devdoc>
public static void Register(IAuthenticationModule authenticationModule)
{
#if FEATURE_MONO_CAS
ExceptionHelper.UnmanagedPermission.Demand();
#endif
Instance.Register(authenticationModule);
}
/// <devdoc>
/// <para>Unregisters authentication modules for an authentication scheme.</para>
/// </devdoc>
public static void Unregister(IAuthenticationModule authenticationModule)
{
#if FEATURE_MONO_CAS
ExceptionHelper.UnmanagedPermission.Demand();
#endif
Instance.Unregister(authenticationModule);
}
/// <devdoc>
/// <para>Unregisters authentication modules for an authentication scheme.</para>
/// </devdoc>
public static void Unregister(string authenticationScheme)
{
#if FEATURE_MONO_CAS
ExceptionHelper.UnmanagedPermission.Demand();
#endif
Instance.Unregister(authenticationScheme);
}
/// <devdoc>
/// <para>
/// Returns a list of registered authentication modules.
/// </para>
/// </devdoc>
public static IEnumerator RegisteredModules
{
get
{
return Instance.RegisteredModules;
}
}
/// <devdoc>
/// <para>
/// Binds an authentication response to a request for pre-authentication.
/// </para>
/// </devdoc>
// Create binding between an authorization response and the module
// generating that response
// This association is used for deciding which module to invoke
// for preauthentication purposes
internal static void BindModule(Uri uri, Authorization response, IAuthenticationModule module)
{
Instance.BindModule(uri, response, module);
}
//
// The method will extract the blob that does correspond to the moduled with the name passed in signature
// parameter. The method avoids confusion arisen from the parameters passed in a quoted string, such as:
// WWW-Authenticate: Digest username="NTLM", realm="wit", NTLM ...
//
[SuppressMessage(
"Microsoft.Globalization", "CA1308", Justification = "Assert-only by check for lower-case signature")]
internal static int FindSubstringNotInQuotes(string challenge, string signature)
{
int index = -1;
Debug.Assert(signature.ToLowerInvariant().Equals(signature, StringComparison.Ordinal),
"'signature' parameter must be lower case");
if (challenge != null && signature != null && challenge.Length >= signature.Length)
{
int firstQuote = -1, secondQuote = -1;
for (int i = 0; i < challenge.Length && index < 0; i++)
{
// Search for the quotes
if (challenge[i] == '\"')
{
if (firstQuote <= secondQuote)
firstQuote = i;
else
secondQuote = i;
}
// We've found both ends of an unquoted segment (could be whole challenge), search inside for the signature.
if (i == challenge.Length - 1 || (challenge[i] == '\"' && firstQuote > secondQuote))
{
// see if the portion of challenge out of the quotes contains
// the signature of the IAuthenticationModule
if (i == challenge.Length - 1)
firstQuote = challenge.Length;
// unquoted segment is too small to hold a scheme name, ie: scheme param="value",a=""
if (firstQuote < secondQuote + 3)
continue;
int checkstart = secondQuote + 1;
int checkLength = firstQuote - secondQuote - 1;
do
{
// Search for the next (partial match) occurance of the signature
index = IndexOf(challenge, signature, checkstart, checkLength);
if (index >= 0)
{
// Verify the signature is a full scheme name match, not a partial match or a parameter name:
if ((index == 0 || challenge[index - 1] == ' ' || challenge[index - 1] == ',') &&
(index + signature.Length == challenge.Length || challenge[index + signature.Length] == ' ' || challenge[index + signature.Length] == ','))
{
break;
}
// Only a partial match / param name, but maybe there is another occurance of the signature later?
checkLength -= index - checkstart + 1;
checkstart = index + 1;
}
} while (index >= 0);
}
}
}
GlobalLog.Print("AuthenticationManager::FindSubstringNotInQuotes(" + challenge + ", " + signature + ")=" + index.ToString());
return index;
}
//
// Helper for FindSubstringNotInQuotes
// Find the FIRST possible index of a signature.
private static int IndexOf(string challenge, string lwrCaseSignature, int start, int count)
{
count += start + 1 - lwrCaseSignature.Length;
for (; start < count; ++start)
{
int i = 0;
for (; i < lwrCaseSignature.Length; ++i)
{
// force a challenge char to lowecase (safe assuming it works on trusted ASCII source)
if ((challenge[start + i] | 0x20) != lwrCaseSignature[i])
break;
}
if (i == lwrCaseSignature.Length)
return start;
}
return -1;
}
//
// this method is called by the IAuthenticationModule implementations
// (mainly Digest) to safely find their list of parameters in a challenge.
// it returns the index of the first ',' that is not included in quotes,
// -1 is returned on error or end of string. on return offset contains the
// index of the first '=' that is not included in quotes, -1 if no '=' was found.
//
internal static int SplitNoQuotes(string challenge, ref int offset)
{
// GlobalLog.Print("SplitNoQuotes([" + challenge + "], " + offset.ToString() + ")");
//
// save offset
//
int realOffset = offset;
//
// default is not found
//
offset = -1;
if (challenge != null && realOffset < challenge.Length)
{
int firstQuote = -1, secondQuote = -1;
for (int i = realOffset; i < challenge.Length; i++)
{
//
// firstQuote>secondQuote means we are in a quoted string
//
if (firstQuote > secondQuote && challenge[i] == '\\' && i + 1 < challenge.Length && challenge[i + 1] == '\"')
{
//
// skip <\"> when in a quoted string
//
i++;
}
else if (challenge[i] == '\"')
{
if (firstQuote <= secondQuote)
{
firstQuote = i;
}
else
{
secondQuote = i;
}
}
else if (challenge[i] == '=' && firstQuote <= secondQuote && offset < 0)
{
offset = i;
}
else if (challenge[i] == ',' && firstQuote <= secondQuote)
{
return i;
}
}
}
return -1;
}
#if !FEATURE_PAL
internal static Authorization GetGroupAuthorization(
IAuthenticationModule thisModule,
string token,
bool finished,
NTAuthentication authSession,
bool shareAuthenticatedConnections,
bool mutualAuth)
{
return new Authorization(
token,
finished,
(shareAuthenticatedConnections) ? null
: (thisModule.GetType().FullName + "/" + authSession.UniqueUserId),
mutualAuth);
}
#endif // !FEATURE_PAL
} // class AuthenticationManager
} // namespace System.Net

View File

@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
// <copyright file="AuthenticationScheme.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Net {
// These are not in sync with the flags IIS uses for the metabase. I guess that's OK.
// For reference IIS actually uses a combination of flags to figure out what challenge to send out:
// AuthAnonymous, AuthBasic, AuthMD5, AuthPassport, AuthNTLM: these are bool values
// NTAuthenticationProviders: this is a string "NTLM", "Kerberos", "Negotiate"
// AuthFlags:
// Basic 0x00000002
// NTLM 0x00000004
// Kerberos 0x00000004
// Negotiate 0x00000004
// Digest 0x00000010
// Passport 0x00000040
[Flags]
public enum AuthenticationSchemes {
None = 0x00000000,
Digest = 0x00000001,
Negotiate = 0x00000002,
Ntlm = 0x00000004,
Basic = 0x00000008,
Anonymous = 0x00008000,
IntegratedWindowsAuthentication = Negotiate | Ntlm,
}
}

View File

@@ -0,0 +1,12 @@
//------------------------------------------------------------------------------
// <copyright file="AuthenticationSchemeSelector.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Net {
#if SECURITY_DEP
public delegate AuthenticationSchemes AuthenticationSchemeSelector(HttpListenerRequest httpRequest);
#endif
}

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
// <copyright file="Authorization.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Net {
/// <devdoc>
/// <para>Used for handling and completing a custom authorization.</para>
/// </devdoc>
public class Authorization {
private string m_Message;
private bool m_Complete;
private string[] m_ProtectionRealm;
private string m_ConnectionGroupId;
private bool m_MutualAuth;
/// <devdoc>
/// <para>
/// Creates a new instance of the <see cref='System.Net.Authorization'/> class with the specified
/// authorization token.
/// </para>
/// </devdoc>
public Authorization(string token) {
m_Message = ValidationHelper.MakeStringNull(token);
m_Complete = true;
}
/// <devdoc>
/// <para>
/// Creates a new instance of the <see cref='System.Net.Authorization'/> class with the specified
/// authorization token and completion status.
/// </para>
/// </devdoc>
public Authorization(string token, bool finished) {
m_Message = ValidationHelper.MakeStringNull(token);
m_Complete = finished;
}
/// <devdoc>
/// <para>
/// Creates a new instance of the <see cref='System.Net.Authorization'/> class with the specified
/// authorization token, completion status, and connection m_ConnectionGroupId identifier.
/// </para>
/// </devdoc>
public Authorization(string token, bool finished, string connectionGroupId): this(token, finished, connectionGroupId, false) {
}
//
internal Authorization(string token, bool finished, string connectionGroupId, bool mutualAuth) {
m_Message = ValidationHelper.MakeStringNull(token);
m_ConnectionGroupId = ValidationHelper.MakeStringNull(connectionGroupId);
m_Complete = finished;
m_MutualAuth = mutualAuth;
}
/// <devdoc>
/// <para>Gets
/// the response returned to the server in response to an authentication
/// challenge.</para>
/// </devdoc>
public string Message {
get { return m_Message;}
}
// used to specify if this Authorization needs a special private server connection,
// identified by this string
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public string ConnectionGroupId {
get { return m_ConnectionGroupId; }
}
/// <devdoc>
/// <para>Gets the completion status of the authorization.</para>
/// </devdoc>
public bool Complete {
get { return m_Complete;}
}
internal void SetComplete(bool complete) {
m_Complete = complete;
}
/// <devdoc>
/// <para>Gets or sets the prefix for Uris that can be authenticated with the <see cref='System.Net.Authorization.Message'/> property.</para>
/// </devdoc>
public string[] ProtectionRealm {
get { return m_ProtectionRealm;}
set {
string[] newValue = ValidationHelper.MakeEmptyArrayNull(value);
m_ProtectionRealm = newValue;
}
}
//
//
public bool MutuallyAuthenticated {
get {
return Complete && m_MutualAuth;
}
set {
m_MutualAuth = value;
}
}
#if MONO
// Temporary bridge to old implementation
internal string ModuleAuthenticationType;
#endif
} // class Authorization
} // namespace System.Net

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
namespace System.Net
{
// The purpose of all derived classes of WebProxyFinder is to determine the PAC file location,
// download and compile the file and then execute it to retrieve the list of proxies for a certain
// Uri.
internal abstract class BaseWebProxyFinder : IWebProxyFinder
{
private AutoWebProxyState state;
private AutoWebProxyScriptEngine engine;
public BaseWebProxyFinder(AutoWebProxyScriptEngine engine)
{
this.engine = engine;
}
public bool IsValid
{
get { return (state == AutoWebProxyState.Completed) || (state == AutoWebProxyState.Uninitialized); }
}
public bool IsUnrecognizedScheme
{
get { return state == AutoWebProxyState.UnrecognizedScheme; }
}
public abstract bool GetProxies(Uri destination, out IList<string> proxyList);
public abstract void Abort();
public virtual void Reset()
{
State = AutoWebProxyState.Uninitialized;
}
public void Dispose()
{
Dispose(true);
}
protected AutoWebProxyState State
{
get { return state; }
set { state = value; }
}
protected AutoWebProxyScriptEngine Engine
{
get { return engine; }
}
protected abstract void Dispose(bool disposing);
protected enum AutoWebProxyState
{
Uninitialized,
DiscoveryFailure,
DownloadFailure,
CompilationFailure,
UnrecognizedScheme,
Completed
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
RequestCache.cs
Abstract:
The file specifies interfaces used to communicate with Request Caching subsystem.
Author:
Alexei Vopilov 21-Dec-2002
Revision History:
Jan 25 2004 - Changed the visibility of the class from public to internal.
--*/
namespace System.Net.Cache {
using System;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Threading;
// The class specifies the contract for a caching storage to participate in the caching protocol.
// The required functionality is to retrieve cached data and update cache based on a string as a Key.
// It is also assumed that cache does storage quota management so it can remove expired cached entries under limited space conditions.
// Note that no implementation methods should block as there is no Async API exposed by this type.
internal abstract class RequestCache {
internal static readonly char[] LineSplits = new char[] {'\r','\n'};
private bool _IsPrivateCache;
private bool _CanWrite;
protected RequestCache( bool isPrivateCache, bool canWrite)
{
_IsPrivateCache = isPrivateCache;
_CanWrite = canWrite;
}
internal bool IsPrivateCache {get {return _IsPrivateCache;}}
internal bool CanWrite {get {return _CanWrite;}}
// Returns a read data stream and metadata associated with a cached entry.
// Returns Stream.Null if there is no entry found.
// <remarks> An opened cache entry be preserved until the stream is closed. </remarks>
//
internal abstract Stream Retrieve(string key, out RequestCacheEntry cacheEntry);
// Returns a write cache stream associated with the string Key.
// Passed parameters allow cache to update an entry metadata accordingly.
// <remarks> The commit operation should happen on the stream closure. </remarks>
//
internal abstract Stream Store(
string key,
long contentLength,
DateTime expiresUtc,
DateTime lastModifiedUtc,
TimeSpan maxStale,
StringCollection entryMetadata,
StringCollection systemMetadata
);
//
// Removes an entry from the cache.
//
internal abstract void Remove(string key);
//
// Updates only metadata associated with a cached entry.
//
internal abstract void Update(
string key,
DateTime expiresUtc,
DateTime lastModifiedUtc,
DateTime lastSynchronizedUtc,
TimeSpan maxStale,
StringCollection entryMetadata,
StringCollection systemMetadata);
//
// Does not throw on failure
internal abstract bool TryRetrieve(string key, out RequestCacheEntry cacheEntry, out Stream readStream);
//
// Does not throw on failure
internal abstract bool TryStore(
string key,
long contentLength,
DateTime expiresUtc,
DateTime lastModifiedUtc,
TimeSpan maxStale,
StringCollection entryMetadata,
StringCollection systemMetadata,
out Stream writeStream);
//
// Does not throw on failure
internal abstract bool TryRemove(string key);
//
// Does not throw on failure
internal abstract bool TryUpdate(
string key,
DateTime expiresUtc,
DateTime lastModifiedUtc,
DateTime lastSynchronizedUtc,
TimeSpan maxStale,
StringCollection entryMetadata,
StringCollection systemMetadata);
//
// This can be looked as a design hole since we have to keep the entry
// locked for the case when we want to update that previously retrieved entry.
// I think RequestCache contract should allow to detect that a new physical cache entry
// does not match to the "entry being updated" and so to should ignore updates on replaced entries.
//
internal abstract void UnlockEntry(Stream retrieveStream);
}
}

View File

@@ -0,0 +1,115 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
RequestCacheEntry.cs
Abstract:
Describes the attributes of a cache entry.
Author:
Alexei Vopilov 21-Dec-2002
Revision History:
Aug 25 2003 moved to a new class, accomodated Whidbey-M3 changes
--*/
namespace System.Net.Cache {
using System;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Threading;
using System.Globalization;
internal class RequestCacheEntry {
private bool m_IsPrivateEntry;
private long m_StreamSize;
private DateTime m_ExpiresUtc;
private int m_HitCount;
private DateTime m_LastAccessedUtc;
private DateTime m_LastModifiedUtc;
private DateTime m_LastSynchronizedUtc;
private TimeSpan m_MaxStale;
private int m_UsageCount;
private bool m_IsPartialEntry;
private StringCollection m_EntryMetadata;
private StringCollection m_SystemMetadata;
internal RequestCacheEntry()
{
m_ExpiresUtc = m_LastAccessedUtc = m_LastModifiedUtc = m_LastSynchronizedUtc = DateTime.MinValue;
}
#if !FEATURE_PAL
// This ctor is for IERequestCache class only that relies on WinInet cache API.
internal RequestCacheEntry(_WinInetCache.Entry entry, bool isPrivateEntry)
{
m_IsPrivateEntry = isPrivateEntry;
m_StreamSize = ((long)entry.Info.SizeHigh<<32) | (long)((ulong)entry.Info.SizeLow);
m_ExpiresUtc = (entry.Info.ExpireTime.IsNull? DateTime.MinValue: DateTime.FromFileTimeUtc(entry.Info.ExpireTime.ToLong()));
m_HitCount = entry.Info.HitRate;
m_LastAccessedUtc= (entry.Info.LastAccessTime.IsNull? DateTime.MinValue: DateTime.FromFileTimeUtc(entry.Info.LastAccessTime.ToLong()));
m_LastModifiedUtc= (entry.Info.LastModifiedTime.IsNull? DateTime.MinValue: DateTime.FromFileTimeUtc(entry.Info.LastModifiedTime.ToLong()));
m_LastSynchronizedUtc= (entry.Info.LastSyncTime.IsNull? DateTime.MinValue: DateTime.FromFileTimeUtc(entry.Info.LastSyncTime.ToLong()));
m_MaxStale = TimeSpan.FromSeconds(entry.Info.U.ExemptDelta);
if (m_MaxStale == Microsoft.Win32.WinInetCache.s_MaxTimeSpanForInt32)
{
m_MaxStale = TimeSpan.MaxValue;
}
m_UsageCount = entry.Info.UseCount;
m_IsPartialEntry = (entry.Info.EntryType & _WinInetCache.EntryType.Sparse) != 0;
}
#endif // !FEATURE_PAL
internal bool IsPrivateEntry {get{return m_IsPrivateEntry;} set{m_IsPrivateEntry = value;}}
internal long StreamSize {get{return m_StreamSize;} set{m_StreamSize = value;}}
internal DateTime ExpiresUtc {get{return m_ExpiresUtc;} set{m_ExpiresUtc = value;}}
internal DateTime LastAccessedUtc {get{return m_LastAccessedUtc;} set{m_LastAccessedUtc = value;}}
internal DateTime LastModifiedUtc {get{return m_LastModifiedUtc;} set{m_LastModifiedUtc = value;}}
internal DateTime LastSynchronizedUtc {get{return m_LastSynchronizedUtc;} set{m_LastSynchronizedUtc = value;}}
internal TimeSpan MaxStale {get{return m_MaxStale;} set{m_MaxStale = value;}}
internal int HitCount {get{return m_HitCount;} set{m_HitCount = value;}}
internal int UsageCount {get{return m_UsageCount;} set{m_UsageCount = value;}}
internal bool IsPartialEntry {get{return m_IsPartialEntry;} set{m_IsPartialEntry = value;}}
internal StringCollection EntryMetadata {get{return m_EntryMetadata;} set{m_EntryMetadata = value;}}
internal StringCollection SystemMetadata {get{return m_SystemMetadata;} set{m_SystemMetadata = value;}}
internal virtual string ToString(bool verbose) {
StringBuilder sb = new StringBuilder(512);
sb.Append("\r\nIsPrivateEntry = ").Append(IsPrivateEntry);
sb.Append("\r\nIsPartialEntry = ").Append(IsPartialEntry);
sb.Append("\r\nStreamSize = ").Append(StreamSize);
sb.Append("\r\nExpires = ").Append(ExpiresUtc == DateTime.MinValue? "": ExpiresUtc.ToString("r", CultureInfo.CurrentCulture));
sb.Append("\r\nLastAccessed = ").Append(LastAccessedUtc == DateTime.MinValue? "": LastAccessedUtc.ToString("r", CultureInfo.CurrentCulture));
sb.Append("\r\nLastModified = ").Append(LastModifiedUtc == DateTime.MinValue? "": LastModifiedUtc.ToString("r", CultureInfo.CurrentCulture));
sb.Append("\r\nLastSynchronized = ").Append(LastSynchronizedUtc == DateTime.MinValue? "": LastSynchronizedUtc.ToString("r", CultureInfo.CurrentCulture));
sb.Append("\r\nMaxStale(sec) = ").Append(MaxStale == TimeSpan.MinValue? "": ((int)MaxStale.TotalSeconds).ToString(NumberFormatInfo.CurrentInfo));
sb.Append("\r\nHitCount = ").Append(HitCount.ToString(NumberFormatInfo.CurrentInfo));
sb.Append("\r\nUsageCount = ").Append(UsageCount.ToString(NumberFormatInfo.CurrentInfo));
sb.Append("\r\n");
if (verbose) {
sb.Append("EntryMetadata:\r\n");
if (m_EntryMetadata != null) {
foreach (string s in m_EntryMetadata) {
sb.Append(s).Append("\r\n");
}
}
sb.Append("---\r\nSystemMetadata:\r\n");
if (m_SystemMetadata != null) {
foreach (string s in m_SystemMetadata) {
sb.Append(s).Append("\r\n");
}
}
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,143 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
RequestCacheManager.cs
Abstract:
The class implements the app domain wide configuration
for request cache aware clients
Author:
Alexei Vopilov 21-Dec-2002
Revision History:
Jan 25 2004 - Changed the visibility of the class from public to internal, compressed unused logic.
--*/
namespace System.Net.Cache {
using System;
using System.Collections;
using System.Net.Configuration;
using System.Configuration;
/// <summary> Specifies app domain-wide default settings for request caching </summary>
internal sealed class RequestCacheManager {
private RequestCacheManager() {}
private static volatile RequestCachingSectionInternal s_CacheConfigSettings;
private static readonly RequestCacheBinding s_BypassCacheBinding = new RequestCacheBinding (null, null, new RequestCachePolicy(RequestCacheLevel.BypassCache));
private static volatile RequestCacheBinding s_DefaultGlobalBinding;
private static volatile RequestCacheBinding s_DefaultHttpBinding;
private static volatile RequestCacheBinding s_DefaultFtpBinding;
//
// ATN: the caller MUST use uri.Scheme as a parameter, otheriwse cannot do schme ref comparision
//
internal static RequestCacheBinding GetBinding(string internedScheme)
{
if (internedScheme == null)
throw new ArgumentNullException("uriScheme");
if (s_CacheConfigSettings == null)
LoadConfigSettings();
if(s_CacheConfigSettings.DisableAllCaching)
return s_BypassCacheBinding;
if (internedScheme.Length == 0)
return s_DefaultGlobalBinding;
if ((object)internedScheme == (object)Uri.UriSchemeHttp || (object)internedScheme == (object)Uri.UriSchemeHttps)
return s_DefaultHttpBinding;
if ((object)internedScheme == (object)Uri.UriSchemeFtp)
return s_DefaultFtpBinding;
return s_BypassCacheBinding;
}
internal static bool IsCachingEnabled
{
get
{
if (s_CacheConfigSettings == null)
LoadConfigSettings();
return !s_CacheConfigSettings.DisableAllCaching;
}
}
//
internal static void SetBinding(string uriScheme, RequestCacheBinding binding)
{
if (uriScheme == null)
throw new ArgumentNullException("uriScheme");
if (s_CacheConfigSettings == null)
LoadConfigSettings();
if(s_CacheConfigSettings.DisableAllCaching)
return;
if (uriScheme.Length == 0)
s_DefaultGlobalBinding = binding;
else if (uriScheme == Uri.UriSchemeHttp || uriScheme == Uri.UriSchemeHttps)
s_DefaultHttpBinding = binding;
else if (uriScheme == Uri.UriSchemeFtp)
s_DefaultFtpBinding = binding;
}
//
private static void LoadConfigSettings()
{
// Any concurent access shall go here and block until we've grabbed the config settings
lock (s_BypassCacheBinding)
{
if (s_CacheConfigSettings == null)
{
RequestCachingSectionInternal settings = RequestCachingSectionInternal.GetSection();
s_DefaultGlobalBinding = new RequestCacheBinding (settings.DefaultCache, settings.DefaultHttpValidator, settings.DefaultCachePolicy);
s_DefaultHttpBinding = new RequestCacheBinding (settings.DefaultCache, settings.DefaultHttpValidator, settings.DefaultHttpCachePolicy);
s_DefaultFtpBinding = new RequestCacheBinding (settings.DefaultCache, settings.DefaultFtpValidator, settings.DefaultFtpCachePolicy);
s_CacheConfigSettings = settings;
}
}
}
}
//
//
internal class RequestCacheBinding {
private RequestCache m_RequestCache;
private RequestCacheValidator m_CacheValidator;
private RequestCachePolicy m_Policy;
internal RequestCacheBinding (RequestCache requestCache, RequestCacheValidator cacheValidator, RequestCachePolicy policy) {
m_RequestCache = requestCache;
m_CacheValidator = cacheValidator;
m_Policy = policy;
}
internal RequestCache Cache {
get {return m_RequestCache;}
}
internal RequestCacheValidator Validator {
get {return m_CacheValidator;}
}
internal RequestCachePolicy Policy {
get {return m_Policy;}
}
}
}

View File

@@ -0,0 +1,298 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
RequestCachePolicy.cs
Abstract:
The class implements caching policy paradigms that is used by all webrequest cache-aware clients
Author:
Alexei Vopilov 21-Dec-2002
Revision History:
4 Dec 2003 - Reworked as per design review.
30 Jul 2004 - Updated to accomodate FTP caching feature
--*/
namespace System.Net.Cache {
using System.Globalization;
// The enum describes cache settings applicable for any webrequest
public enum RequestCacheLevel
{
// Default cache behavior determined by the protocol class
Default = 0,
// Bypass the cache completely
BypassCache = 1,
// Only serve requests from cache, an exception is thrown if not found
CacheOnly = 2,
// Serve from the cache, but will [....] up with the server if not found
CacheIfAvailable = 3,
// Attempt to revalidate cache with the server, reload if unable to
Revalidate = 4,
// Reload the data from the origin server
Reload = 5,
// Bypass the cache and removing existing entries in the cache
NoCacheNoStore = 6
}
//
// Common request cache policy used for caching of Http, FTP, etc.
//
public class RequestCachePolicy
{
private RequestCacheLevel m_Level;
//
// Public stuff
//
public RequestCachePolicy(): this (RequestCacheLevel.Default)
{
}
public RequestCachePolicy(RequestCacheLevel level)
{
if (level < RequestCacheLevel.Default || level > RequestCacheLevel.NoCacheNoStore)
throw new ArgumentOutOfRangeException("level");
m_Level = level;
}
//
public RequestCacheLevel Level
{
get {
return m_Level;
}
}
//
public override string ToString()
{
return "Level:" + m_Level.ToString();
}
//
// Internal stuff
//
//
#if TRAVE
/*
// Consider removing.
internal static string ToString(RequestCachePolicy Policy)
{
if (Policy == null) {
return "null";
}
return Policy.ToString();
}
*/
#endif
}
// The enum describes cache settings for http
public enum HttpRequestCacheLevel
{
// Default cache behavior, server fresh response fomr cache, otherwise attempt
// to revalidate with the server or reload
Default = 0,
// Bypass the cache completely
BypassCache = 1,
// Only serve requests from cache, an exception is thrown if not found
CacheOnly = 2,
// Serve from the cache, but will [....] up with the server if not found
CacheIfAvailable = 3,
// Validate cached data with the server even if it looks fresh
Revalidate = 4,
// Reload the data from the origin server
Reload = 5,
// Bypass the cache and removing existing entries in the cache
NoCacheNoStore = 6,
// Serve from cache, or the next cache along the path
CacheOrNextCacheOnly= 7,
// Reload the data either from the origin server or from an uplevel cache
//This is equvalent to Cache-Control:MaxAge=0 HTTP semantic
Refresh = 8,
}
//
// CacheAgeControl is used to specify preferences with respect of cached item age and freshness.
//
public enum HttpCacheAgeControl {
// Invalid value. Indicates the enum is not initialized
None = 0x0,
// Cached item must be at least fresh for specified period since now
MinFresh = 0x1,
// Cached item must be fresh and it's age must not exceed specified period
MaxAge = 0x2,
// Cached item may be not fresh but it's expiration must not exceed specified period
MaxStale = 0x4,
// Cached item must fresh for some period in future and it's age must be less than specified
MaxAgeAndMinFresh = 0x3, // MaxAge|MinFresh,
// Cached item may be found as stale for some period but it's age must be less than specified
MaxAgeAndMaxStale = 0x6, // MaxAge|MaxStale,
}
//
// HTTP cache policy that expresses RFC2616 HTTP caching semantic
//
public class HttpRequestCachePolicy: RequestCachePolicy {
internal static readonly HttpRequestCachePolicy BypassCache = new HttpRequestCachePolicy(HttpRequestCacheLevel.BypassCache);
//Private members
private HttpRequestCacheLevel m_Level = HttpRequestCacheLevel.Default;
private DateTime m_LastSyncDateUtc = DateTime.MinValue;
private TimeSpan m_MaxAge = TimeSpan.MaxValue;
private TimeSpan m_MinFresh = TimeSpan.MinValue;
private TimeSpan m_MaxStale = TimeSpan.MinValue;
//
// Public stuff
//
public HttpRequestCachePolicy():this(HttpRequestCacheLevel.Default)
{
}
//
public HttpRequestCachePolicy(HttpRequestCacheLevel level): base(MapLevel(level))
{
m_Level = level;
}
//
// Creates an automatic cache policy that is bound to a simples age control
//
public HttpRequestCachePolicy(HttpCacheAgeControl cacheAgeControl, TimeSpan ageOrFreshOrStale):this(HttpRequestCacheLevel.Default)
{
switch(cacheAgeControl) {
case HttpCacheAgeControl.MinFresh:
m_MinFresh = ageOrFreshOrStale;
break;
case HttpCacheAgeControl.MaxAge:
m_MaxAge = ageOrFreshOrStale;
break;
case HttpCacheAgeControl.MaxStale:
m_MaxStale = ageOrFreshOrStale;
break;
default:
throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "HttpCacheAgeControl"), "cacheAgeControl");
}
}
//
// Creates an automatic cache policy that is bound to a complex age control
//
public HttpRequestCachePolicy(HttpCacheAgeControl cacheAgeControl, TimeSpan maxAge, TimeSpan freshOrStale):this(HttpRequestCacheLevel.Default)
{
switch(cacheAgeControl) {
case HttpCacheAgeControl.MinFresh:
m_MinFresh = freshOrStale;
break;
case HttpCacheAgeControl.MaxAge:
m_MaxAge = maxAge;
break;
case HttpCacheAgeControl.MaxStale:
m_MaxStale = freshOrStale;
break;
case HttpCacheAgeControl.MaxAgeAndMinFresh:
m_MaxAge = maxAge;
m_MinFresh = freshOrStale;
break;
case HttpCacheAgeControl.MaxAgeAndMaxStale:
m_MaxAge = maxAge;
m_MaxStale = freshOrStale;
break;
default:
throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "HttpCacheAgeControl"), "cacheAgeControl");
}
}
//
// Creates an automatic cache policy with the Date Synchronization requirement
//
public HttpRequestCachePolicy(DateTime cacheSyncDate):this(HttpRequestCacheLevel.Default)
{
m_LastSyncDateUtc = cacheSyncDate.ToUniversalTime();
}
//
//
//
public HttpRequestCachePolicy(HttpCacheAgeControl cacheAgeControl, TimeSpan maxAge, TimeSpan freshOrStale, DateTime cacheSyncDate)
:this(cacheAgeControl, maxAge, freshOrStale)
{
m_LastSyncDateUtc = cacheSyncDate.ToUniversalTime();
}
//
// Properties
//
public new HttpRequestCacheLevel Level
{
get {
return m_Level;
}
}
//
// Requires revalidation of items stored before lastSyncDate
//
public DateTime CacheSyncDate {
get {
if (m_LastSyncDateUtc == DateTime.MinValue || m_LastSyncDateUtc == DateTime.MaxValue) {
return m_LastSyncDateUtc;
}
return m_LastSyncDateUtc.ToLocalTime();}
}
//
internal DateTime InternalCacheSyncDateUtc {
get {return m_LastSyncDateUtc;}
}
//
// Specifies age policy according to HTTP 1.1 RFC caching semantic
//
public TimeSpan MaxAge {
get {return m_MaxAge;}
}
//
// Specifies age policy according to HTTP 1.1 RFC caching semantic
//
public TimeSpan MinFresh {
get {return m_MinFresh;}
}
//
// Specifies age policy according to HTTP 1.1 RFC caching semantic
//
public TimeSpan MaxStale {
get {return m_MaxStale;}
}
//
//
//
public override string ToString()
{
return "Level:" + m_Level.ToString() +
(m_MaxAge == TimeSpan.MaxValue? string.Empty: " MaxAge:" + m_MaxAge.ToString()) +
(m_MinFresh == TimeSpan.MinValue? string.Empty: " MinFresh:" + m_MinFresh.ToString()) +
(m_MaxStale == TimeSpan.MinValue? string.Empty: " MaxStale:" + m_MaxStale.ToString()) +
(CacheSyncDate==DateTime.MinValue? string.Empty: " CacheSyncDate:" + CacheSyncDate.ToString(CultureInfo.CurrentCulture));
}
//
//
//
private static RequestCacheLevel MapLevel(HttpRequestCacheLevel level)
{
if (level <= HttpRequestCacheLevel.NoCacheNoStore)
return (RequestCacheLevel) level;
if (level == HttpRequestCacheLevel.CacheOrNextCacheOnly)
return RequestCacheLevel.CacheOnly;
if (level == HttpRequestCacheLevel.Refresh)
return RequestCacheLevel.Reload;
throw new ArgumentOutOfRangeException("level");
}
}
}

View File

@@ -0,0 +1,234 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
RequestCacheValidator.cs
Abstract:
The file specifies the contract for plugged cache validation logic.
Author:
Alexei Vopilov 21-Dec-2002
Revision History:
Aug 25 2003 - Moved into a separate file and implemented Whidbey M3 changes
Jan 25 2004 - Changed the visibility of the class from public to internal.
--*/
namespace System.Net.Cache {
using System;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Threading;
//
// We need Undefined value because sometime a cache entry does not provide a clue when it should expire
// not flags!
internal enum CacheFreshnessStatus
{
Undefined = 0,
Fresh = 1,
Stale = 2
}
//
// These are valus that can be returned from validation methods.
// Most validation methods can only return a subset of below values.
//
// not flags!
internal enum CacheValidationStatus
{
DoNotUseCache = 0, //Cache is not used for this request and response is not cached.
Fail = 1, //Fail this request (allows a protocol to generate own exception)
DoNotTakeFromCache = 2, //Don't used caches value for this request
RetryResponseFromCache = 3, //Retry cache lookup using changed cache key
RetryResponseFromServer = 4, //Retry this request as the result of invalid response received
ReturnCachedResponse = 5, //Return cached response to the application
CombineCachedAndServerResponse = 6, //Combine cached and live responses for this request
CacheResponse = 7, //Replace cache entry with received live response
UpdateResponseInformation = 8, //Update Metadata of cache entry using live response headers
RemoveFromCache = 9, //Remove cache entry referenced to by a cache key.
DoNotUpdateCache = 10, //Do nothing on cache update.
Continue = 11 //Proceed to the next protocol stage.
}
/// <summary>
/// <para>
/// This class reserves a pattern for all WebRequest related cache validators.
/// All exposed protected methods are virtual.
/// If a derived class method does not call the base method implementation,
/// then the base class context may not be updated so it's recommended suppressing the base
/// methods for all subsequent calls on this class.
/// </para>
/// </summary>
internal abstract class RequestCacheValidator {
internal WebRequest _Request;
internal WebResponse _Response;
internal Stream _CacheStream;
private RequestCachePolicy _Policy;
private Uri _Uri;
private String _CacheKey;
private RequestCacheEntry _CacheEntry;
private int _ResponseCount;
private CacheValidationStatus _ValidationStatus;
private CacheFreshnessStatus _CacheFreshnessStatus;
private long _CacheStreamOffset;
private long _CacheStreamLength;
private bool _StrictCacheErrors;
private TimeSpan _UnspecifiedMaxAge;
/*-------------- public members -------------*/
internal abstract RequestCacheValidator CreateValidator();
/*
// Consider removing.
protected RequestCacheValidator(): this(false, TimeSpan.FromDays(1))
{
}
*/
protected RequestCacheValidator(bool strictCacheErrors, TimeSpan unspecifiedMaxAge)
{
_StrictCacheErrors = strictCacheErrors;
_UnspecifiedMaxAge = unspecifiedMaxAge;
_ValidationStatus = CacheValidationStatus.DoNotUseCache;
_CacheFreshnessStatus = CacheFreshnessStatus.Undefined;
}
//public
internal bool StrictCacheErrors
{
get {return _StrictCacheErrors;}
}
//
// This would help cache validation when the entry does
// not have any expiration mechanism defined.
//public
internal TimeSpan UnspecifiedMaxAge
{
get {return _UnspecifiedMaxAge;}
}
/*------------- get-only protected properties -------------*/
protected internal Uri Uri {get {return _Uri;}}
protected internal WebRequest Request {get {return _Request; }}
protected internal WebResponse Response {get {return _Response; }}
protected internal RequestCachePolicy Policy {get {return _Policy; }}
protected internal int ResponseCount {get {return _ResponseCount;}}
protected internal CacheValidationStatus ValidationStatus {get {return _ValidationStatus;}}
protected internal CacheFreshnessStatus CacheFreshnessStatus {get {return _CacheFreshnessStatus;}}
protected internal RequestCacheEntry CacheEntry {get {return _CacheEntry;}}
/*------------- protected methods and settable protected properties ------------*/
protected internal Stream CacheStream
{
get {return _CacheStream;}
set {_CacheStream = value;}
}
//
protected internal long CacheStreamOffset
{
get {return _CacheStreamOffset;}
set {_CacheStreamOffset = value;}
}
//
protected internal long CacheStreamLength
{
get {return _CacheStreamLength;}
set {_CacheStreamLength = value;}
}
//
protected internal string CacheKey
{
get {return _CacheKey;}
/*
// Consider removing.
set
{
// Security: Setting a cache key would allow reading an arbitrary cache location
//new RequestCachePermission(RequestCacheActions.CacheReadWrite, value).Demand();
_CacheKey = value;
}
*/
}
//
/*-------------- protected virtual methods -------------*/
//
protected internal abstract CacheValidationStatus ValidateRequest();
//
protected internal abstract CacheFreshnessStatus ValidateFreshness();
//
protected internal abstract CacheValidationStatus ValidateCache();
//
protected internal abstract CacheValidationStatus ValidateResponse();
//
protected internal abstract CacheValidationStatus RevalidateCache();
//
protected internal abstract CacheValidationStatus UpdateCache();
//
protected internal virtual void FailRequest(WebExceptionStatus webStatus)
{
if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_failing_request_with_exception, webStatus.ToString()));
if (webStatus == WebExceptionStatus.CacheEntryNotFound)
throw ExceptionHelper.CacheEntryNotFoundException;
else if (webStatus == WebExceptionStatus.RequestProhibitedByCachePolicy)
throw ExceptionHelper.RequestProhibitedByCachePolicyException;
throw new WebException(NetRes.GetWebStatusString("net_requestaborted", webStatus), webStatus);
}
/*-------------- internal members -------------*/
//
internal void FetchRequest(Uri uri, WebRequest request)
{
_Request = request;
_Policy = request.CachePolicy;
_Response = null;
_ResponseCount = 0;
_ValidationStatus = CacheValidationStatus.DoNotUseCache;
_CacheFreshnessStatus = CacheFreshnessStatus.Undefined;
_CacheStream = null;
_CacheStreamOffset = 0L;
_CacheStreamLength = 0L;
if (!uri.Equals(_Uri))
{
// it's changed from previous call
_CacheKey = uri.GetParts(UriComponents.AbsoluteUri, UriFormat.Unescaped);
}
_Uri = uri;
}
//
internal void FetchCacheEntry(RequestCacheEntry fetchEntry)
{
_CacheEntry = fetchEntry;
}
internal void FetchResponse(WebResponse fetchResponse)
{
++_ResponseCount;
_Response = fetchResponse;
}
internal void SetFreshnessStatus(CacheFreshnessStatus status)
{
_CacheFreshnessStatus = status;
}
internal void SetValidationStatus(CacheValidationStatus status)
{
_ValidationStatus = status;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
e4ddb3630aff314e7f6d078dd7c07b6e8f701d04

Some files were not shown because too many files have changed in this diff Show More