IncomingWebRequestContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / ServiceModel / Web / IncomingWebRequestContext.cs / 1305376 / IncomingWebRequestContext.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
#pragma warning disable 1634, 1691
 
namespace System.ServiceModel.Web
{ 
    using System; 
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Net;
    using System.Net.Mime;
    using System.Runtime; 
    using System.ServiceModel;
    using System.ServiceModel.Channels; 
    using System.Collections.ObjectModel; 

    public class IncomingWebRequestContext 
    {
        static readonly string HttpGetMethod = "GET";
        static readonly string HttpHeadMethod = "HEAD";
        static readonly string HttpPutMethod = "PUT"; 
        static readonly string HttpPostMethod = "POST";
        static readonly string HttpDeleteMethod = "DELETE"; 
 
        Collection cachedAcceptHeaderElements;
        string acceptHeaderWhenHeaderElementsCached; 
        internal const string UriTemplateMatchResultsPropertyName = "UriTemplateMatchResults";
        OperationContext operationContext;

        internal IncomingWebRequestContext(OperationContext operationContext) 
        {
            Fx.Assert(operationContext != null, "operationContext is null"); 
            this.operationContext = operationContext; 
        }
 
        public string Accept
        {
            get { return EnsureMessageProperty().Headers[HttpRequestHeader.Accept]; }
        } 

        public long ContentLength 
        { 
            get { return long.Parse(this.EnsureMessageProperty().Headers[HttpRequestHeader.ContentLength], CultureInfo.InvariantCulture); }
        } 

        public string ContentType
        {
            get { return this.EnsureMessageProperty().Headers[HttpRequestHeader.ContentType]; } 
        }
 
        public IEnumerable IfMatch 
        {
            get 
            {
                string ifMatchHeader = MessageProperty.Headers[HttpRequestHeader.IfMatch];
                return (string.IsNullOrEmpty(ifMatchHeader)) ? null : QuoteAwareStringSplit(ifMatchHeader);
            } 
        }
 
        public IEnumerable IfNoneMatch 
        {
            get 
            {
                string ifNoneMatchHeader = MessageProperty.Headers[HttpRequestHeader.IfNoneMatch];
                return (string.IsNullOrEmpty(ifNoneMatchHeader)) ? null : QuoteAwareStringSplit(ifNoneMatchHeader);
            } 
        }
 
        public DateTime? IfModifiedSince 
        {
            get 
            {
                string dateTime = this.MessageProperty.Headers[HttpRequestHeader.IfModifiedSince];
                if (!string.IsNullOrEmpty(dateTime))
                { 
                    DateTime parsedDateTime;
                    if (HttpDateParse.ParseHttpDate(dateTime, out parsedDateTime)) 
                    { 
                        return parsedDateTime;
                    } 
                }
                return null;
            }
        } 

        public DateTime? IfUnmodifiedSince 
        { 
            get
            { 
                string dateTime = this.MessageProperty.Headers[HttpRequestHeader.IfUnmodifiedSince];
                if (!string.IsNullOrEmpty(dateTime))
                {
                    DateTime parsedDateTime; 
                    if (HttpDateParse.ParseHttpDate(dateTime, out parsedDateTime))
                    { 
                        return parsedDateTime; 
                    }
                } 
                return null;
            }
        }
 
        public WebHeaderCollection Headers
        { 
            get { return this.EnsureMessageProperty().Headers; } 
        }
 
        public string Method
        {
            get { return this.EnsureMessageProperty().Method; }
        } 

        public UriTemplateMatch UriTemplateMatch 
        { 
            get
            { 
                if (this.operationContext.IncomingMessageProperties.ContainsKey(UriTemplateMatchResultsPropertyName))
                {
                    return this.operationContext.IncomingMessageProperties[UriTemplateMatchResultsPropertyName] as UriTemplateMatch;
                } 
                else
                { 
                    return null; 
                }
            } 
            set
            {
                this.operationContext.IncomingMessageProperties[UriTemplateMatchResultsPropertyName] = value;
            } 
        }
 
        public string UserAgent 
        {
            get { return this.EnsureMessageProperty().Headers[HttpRequestHeader.UserAgent]; } 
        }

        HttpRequestMessageProperty MessageProperty
        { 
            get
            { 
                if (operationContext.IncomingMessageProperties == null) 
                {
                    return null; 
                }
                if (!operationContext.IncomingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name))
                {
                    return null; 
                }
                return operationContext.IncomingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; 
            } 
        }
 
        public void CheckConditionalRetrieve(string entityTag)
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtagFromString(entityTag);
            CheckConditionalRetrieveWithValidatedEtag(validEtag); 
        }
 
        public void CheckConditionalRetrieve(int entityTag) 
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag); 
            CheckConditionalRetrieveWithValidatedEtag(validEtag);
        }

        public void CheckConditionalRetrieve(long entityTag) 
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag); 
            CheckConditionalRetrieveWithValidatedEtag(validEtag); 
        }
 
        public void CheckConditionalRetrieve(Guid entityTag)
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
            CheckConditionalRetrieveWithValidatedEtag(validEtag); 
        }
 
        public void CheckConditionalRetrieve(DateTime lastModified) 
        {
            if (!string.Equals(this.Method, IncomingWebRequestContext.HttpGetMethod, StringComparison.OrdinalIgnoreCase) && 
                !string.Equals(this.Method, IncomingWebRequestContext.HttpHeadMethod, StringComparison.OrdinalIgnoreCase))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR2.GetString(SR2.ConditionalRetrieveGetAndHeadOnly, this.Method))); 
            }
 
            DateTime? ifModifiedSince = this.IfModifiedSince; 
            if (ifModifiedSince.HasValue)
            { 
                long ticksDifference = lastModified.ToUniversalTime().Ticks - ifModifiedSince.Value.ToUniversalTime().Ticks;
                if (ticksDifference < TimeSpan.TicksPerSecond)
                {
                    WebOperationContext.Current.OutgoingResponse.LastModified = lastModified; 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.NotModified));
                } 
            } 
        }
 
        public void CheckConditionalUpdate(string entityTag)
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtagFromString(entityTag);
            CheckConditionalUpdateWithValidatedEtag(validEtag); 
        }
 
        public void CheckConditionalUpdate(int entityTag) 
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag); 
            CheckConditionalUpdateWithValidatedEtag(validEtag);
        }

        public void CheckConditionalUpdate(long entityTag) 
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag); 
            CheckConditionalUpdateWithValidatedEtag(validEtag); 
        }
 
        public void CheckConditionalUpdate(Guid entityTag)
        {
            string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
            CheckConditionalUpdateWithValidatedEtag(validEtag); 
        }
 
        public Collection GetAcceptHeaderElements() 
        {
            string acceptHeader = this.Accept; 
            if (cachedAcceptHeaderElements == null ||
                (!string.Equals(acceptHeaderWhenHeaderElementsCached, acceptHeader, StringComparison.OrdinalIgnoreCase)))
            {
                if (string.IsNullOrEmpty(acceptHeader)) 
                {
                    cachedAcceptHeaderElements = new Collection(); 
                    acceptHeaderWhenHeaderElementsCached = acceptHeader; 
                }
                else 
                {
                    List contentTypeList = new List();
                    int offset = 0;
                    while (true) 
                    {
                        string nextItem = QuoteAwareSubString(acceptHeader, ref offset); 
                        if (nextItem == null) 
                        {
                            break; 
                        }

                        ContentType contentType = GetContentTypeOrNull(nextItem);
                        if (contentType != null) 
                        {
                            contentTypeList.Add(contentType); 
                        } 
                    }
 
                    contentTypeList.Sort(new AcceptHeaderElementComparer());
                    cachedAcceptHeaderElements = new Collection(contentTypeList);
                    acceptHeaderWhenHeaderElementsCached = acceptHeader;
                } 
            }
            return cachedAcceptHeaderElements; 
        } 

        HttpRequestMessageProperty EnsureMessageProperty() 
        {
            if (this.MessageProperty == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( 
                    SR2.GetString(SR2.HttpContextNoIncomingMessageProperty, typeof(HttpRequestMessageProperty).Name)));
            } 
            return this.MessageProperty; 
        }
 
        // This method extracts substrings from an HTTP header starting at the offset
        // and up until the next comma in the header.  The sub string extraction is
        // quote aware such that commas inside quoted-strings are ignored.  On return,
        // offset points to the next char beyond the comma of the substring returned 
        // and may point beyond the length of the header.
        internal static string QuoteAwareSubString(string header, ref int offset) 
        { 
            // this method will filter out empty-string and white-space-only items in
            // the header.  For example "x,,y" and "x, ,y" would result in just "x" and "y" 
            // substrings being returned.

            if (string.IsNullOrEmpty(header) || offset >= header.Length)
            { 
                return null;
            } 
 
            int startIndex = (offset > 0) ? offset : 0;
 
            // trim whitespace and commas from the begining of the item
            while (char.IsWhiteSpace(header[startIndex]) || header[startIndex] == ',')
            {
                startIndex++; 
                if (startIndex >= header.Length)
                { 
                    return null; 
                }
            } 

            int endIndex = startIndex;
            bool insideQuotes = false;
 
            while (endIndex < header.Length)
            { 
                if (header[endIndex] == '\"' && 
                   (!insideQuotes || endIndex == 0 || header[endIndex - 1] != '\\'))
                { 
                    insideQuotes = !insideQuotes;
                }
                else if (header[endIndex] == ',' && !insideQuotes)
                { 
                    break;
                } 
                endIndex++; 
            }
            offset = endIndex + 1; 

            // trim whitespace from the end of the item; the substring is guaranteed to
            // have at least one non-whitespace character
            while (char.IsWhiteSpace(header[endIndex - 1])) 
            {
                endIndex--; 
            } 

            return header.Substring(startIndex, endIndex - startIndex); 
        }

        internal static List QuoteAwareStringSplit(string header)
        { 
            List subStrings = new List();
            int offset = 0; 
            while (true) 
            {
                string subString = QuoteAwareSubString(header, ref offset); 
                if (subString == null)
                {
                    break;
                } 
                subStrings.Add(subString);
            } 
 
            return subStrings;
        } 

        internal static ContentType GetContentType(string contentType)
        {
            string contentTypeTrimmed = contentType.Trim(); 
            if (!string.IsNullOrEmpty(contentTypeTrimmed))
            { 
                return GetContentTypeOrNull(contentTypeTrimmed); 
            }
            return null; 
        }

        static ContentType GetContentTypeOrNull(string contentType)
        { 
            try
            { 
                Fx.Assert(contentType == contentType.Trim(), "The ContentType input argument should already be trimmed."); 
                Fx.Assert(!string.IsNullOrEmpty(contentType), "The ContentType input argument should not be null or empty.");
                ContentType contentTypeToReturn = new ContentType(contentType); 

                // Need to check for "*/" because the ContentType constructor doesn't catch this
                string[] typeAndSubType = contentTypeToReturn.MediaType.Split('/');
                Fx.Assert(typeAndSubType.Length == 2, "The creation of the ContentType would have failed if there wasn't a type and subtype."); 
                if (typeAndSubType[0][0] == '*' && typeAndSubType[0].Length == 1 &&
                    !(typeAndSubType[1][0] == '*' && typeAndSubType[1].Length == 1)) 
                { 
                    //
 


                    // throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new FormatException(
                    // SR2.GetString(SR2.InvalidContentType, contentType))); 
                    return null;
                } 
                return contentTypeToReturn; 
            }
            catch (FormatException e) 
            {
                // Return null to indicate that the content type creation failed
                System.ServiceModel.DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning);
            } 
            return null;
        } 
 
        void CheckConditionalRetrieveWithValidatedEtag(string entityTag)
        { 
            if (!string.Equals(this.Method, IncomingWebRequestContext.HttpGetMethod, StringComparison.OrdinalIgnoreCase) &&
                !string.Equals(this.Method, IncomingWebRequestContext.HttpHeadMethod, StringComparison.OrdinalIgnoreCase))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( 
                    SR2.GetString(SR2.ConditionalRetrieveGetAndHeadOnly, this.Method)));
            } 
 
            if (!string.IsNullOrEmpty(entityTag))
            { 
                string entityTagHeader = this.Headers[HttpRequestHeader.IfNoneMatch];
                if (!string.IsNullOrEmpty(entityTagHeader))
                {
                    if (IsWildCardCharacter(entityTagHeader) || 
                        DoesHeaderContainEtag(entityTagHeader, entityTag))
                    { 
                        // set response entityTag directly because it has already been validated 
                        WebOperationContext.Current.OutgoingResponse.ETag = entityTag;
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.NotModified)); 
                    }
                }
            }
        } 

        void CheckConditionalUpdateWithValidatedEtag(string entityTag) 
        { 
            bool isPutMethod = string.Equals(this.Method, IncomingWebRequestContext.HttpPutMethod, StringComparison.OrdinalIgnoreCase);
            if (!isPutMethod && 
                !string.Equals(this.Method, IncomingWebRequestContext.HttpPostMethod, StringComparison.OrdinalIgnoreCase) &&
                !string.Equals(this.Method, IncomingWebRequestContext.HttpDeleteMethod, StringComparison.OrdinalIgnoreCase))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( 
                    SR2.GetString(SR2.ConditionalUpdatePutPostAndDeleteOnly, this.Method)));
            } 
 
            string headerOfInterest;
 
            // if the current entityTag is null then the resource doesn't currently exist and the
            //   a PUT request should only succeed if If-None-Match equals '*'.
            if (isPutMethod && string.IsNullOrEmpty(entityTag))
            { 
                headerOfInterest = this.Headers[HttpRequestHeader.IfNoneMatch];
                if (string.IsNullOrEmpty(headerOfInterest) || 
                    !IsWildCardCharacter(headerOfInterest)) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.PreconditionFailed)); 
                }
            }
            else
            { 
                // all remaining cases are with an If-Match header
                headerOfInterest = this.Headers[HttpRequestHeader.IfMatch]; 
                if (string.IsNullOrEmpty(headerOfInterest) || 
                    (!IsWildCardCharacter(headerOfInterest) &&
                    !DoesHeaderContainEtag(headerOfInterest, entityTag))) 
                {
                    // set response entityTag directly because it has already been validated
                    WebOperationContext.Current.OutgoingResponse.ETag = entityTag;
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.PreconditionFailed)); 
                }
            } 
 
        }
 
        static bool DoesHeaderContainEtag(string header, string entityTag)
        {
            int offset = 0;
            while (true) 
            {
                string nextEntityTag = IncomingWebRequestContext.QuoteAwareSubString(header, ref offset); 
                if (nextEntityTag == null) 
                {
                    break; 
                }
                if (string.Equals(nextEntityTag, entityTag, StringComparison.Ordinal))
                {
                    return true; 
                }
            } 
 
            return false;
        } 

        static bool IsWildCardCharacter(string header)
        {
            return (header.Trim() == "*"); 
        }
 
        class AcceptHeaderElementComparer : IComparer 
        {
            static NumberStyles numberStyles = NumberStyles.AllowDecimalPoint; 

            public int Compare(ContentType x, ContentType y)
            {
                string[] xTypeSubType = x.MediaType.Split('/'); 
                string[] yTypeSubType = y.MediaType.Split('/');
 
                Fx.Assert(xTypeSubType.Length == 2, "The creation of the ContentType would have failed if there wasn't a type and subtype."); 
                Fx.Assert(yTypeSubType.Length == 2, "The creation of the ContentType would have failed if there wasn't a type and subtype.");
 
                if (string.Equals(xTypeSubType[0], yTypeSubType[0], StringComparison.OrdinalIgnoreCase))
                {
                    if (string.Equals(xTypeSubType[1], yTypeSubType[1], StringComparison.OrdinalIgnoreCase))
                    { 
                        // need to check the number of parameters to determine which is more specific
                        bool xHasParam = HasParameters(x); 
                        bool yHasParam = HasParameters(y); 
                        if (xHasParam && !yHasParam)
                        { 
                            return 1;
                        }
                        else if (!xHasParam && yHasParam)
                        { 
                            return -1;
                        } 
                    } 
                    else
                    { 
                        if (xTypeSubType[1][0] == '*' && xTypeSubType[1].Length == 1)
                        {
                            return 1;
                        } 
                        if (yTypeSubType[1][0] == '*' && yTypeSubType[1].Length == 1)
                        { 
                            return -1; 
                        }
                    } 
                }
                else if (xTypeSubType[0][0] == '*' && xTypeSubType[0].Length == 1)
                {
                    return 1; 
                }
                else if (yTypeSubType[0][0] == '*' && yTypeSubType[0].Length == 1) 
                { 
                    return -1;
                } 

                decimal qualityDifference = GetQualityFactor(x) - GetQualityFactor(y);
                if (qualityDifference < 0)
                { 
                    return 1;
                } 
                else if (qualityDifference > 0) 
                {
                    return -1; 
                }
                return 0;
            }
 
            decimal GetQualityFactor(ContentType contentType)
            { 
                decimal result; 
                foreach (string key in contentType.Parameters.Keys)
                { 
                    if (string.Equals("q", key, StringComparison.OrdinalIgnoreCase))
                    {
                        if (decimal.TryParse(contentType.Parameters[key], numberStyles, CultureInfo.InvariantCulture, out result) &&
                            (result <= (decimal)1.0)) 
                        {
                            return result; 
                        } 
                    }
                } 

                return (decimal)1.0;
            }
 
            bool HasParameters(ContentType contentType)
            { 
                int number = 0; 
                foreach (string param in contentType.Parameters.Keys)
                { 
                    if (!string.Equals("q", param, StringComparison.OrdinalIgnoreCase))
                    {
                        number++;
                    } 
                }
 
                return (number > 0); 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK