예제 #1
0
        /// <summary>
        /// Validates an <see cref="ODataFeed"/> to ensure all required information is specified and valid.
        /// </summary>
        /// <param name="feed">The feed to validate.</param>
        /// <param name="writingRequest">Flag indicating whether the feed is written as part of a request or a response.</param>
        /// <param name="version">The version of the OData protocol used for checking.</param>
        internal static void ValidateFeed(ODataFeed feed, bool writingRequest, ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(feed != null, "feed != null");

            // Verify non-empty ID
            if (string.IsNullOrEmpty(feed.Id))
            {
                throw new ODataException(Strings.ODataWriter_FeedsMustHaveNonEmptyId);
            }

            // Verify next link
            if (feed.NextPageLink != null)
            {
                // Check that NextPageLink is not set for requests
                if (writingRequest)
                {
                    throw new ODataException(Strings.ODataWriterCore_NextPageLinkInRequest);
                }

                // Verify version requirements
                ODataVersionChecker.CheckServerPaging(version);
            }
        }
예제 #2
0
        /// <summary>
        /// Validates an <see cref="ODataAssociationLink"/> to ensure all required information is specified and valid.
        /// </summary>
        /// <param name="associationLink">The association link to validate.</param>
        /// <param name="version">The version of the OData protocol used for checking.</param>
        internal static void ValidateAssociationLink(ODataAssociationLink associationLink, ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();

            ODataVersionChecker.CheckAssociationLinks(version);

            // null link can not appear in the enumeration
            if (associationLink == null)
            {
                throw new ODataException(Strings.ODataWriter_AssociationLinkMustNotBeNull);
            }

            // Association link must have a non-empty name
            if (string.IsNullOrEmpty(associationLink.Name))
            {
                throw new ODataException(Strings.ODataWriter_AssociationLinkMustSpecifyName);
            }

            // Association link must specify the Url
            if (associationLink.Url == null)
            {
                throw new ODataException(Strings.ODataWriter_AssociationLinkMustSpecifyUrl);
            }
        }
예제 #3
0
 /// <summary>
 /// Returns a value of an HTTP header.
 /// </summary>
 /// <param name="headerName">The name of the header to get.</param>
 /// <returns>The value of the HTTP header, or null if no such header was present on the message.</returns>
 internal override string GetHeader(string headerName)
 {
     DebugUtils.CheckNoExternalCallers();
     return(this.requestMessage.GetHeader(headerName));
 }
예제 #4
0
        /// <summary>Converts the specified value to a serializable string in ATOM format.</summary>
        /// <param name="value">Non-null value to convert.</param>
        /// <param name="result">The specified value converted to an ATOM string.</param>
        /// <param name="preserveWhitespace">A flag indicating whether whitespace needs to be preserved.</param>
        /// <returns>boolean value indicating conversion successful conversion</returns>
        internal static bool TryConvertPrimitiveToString(object value, out string result, out bool preserveWhitespace)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(value != null, "value != null");
            result             = null;
            preserveWhitespace = false;

            TypeCode typeCode = Type.GetTypeCode(value.GetType());

            switch (typeCode)
            {
            case TypeCode.Boolean:
                result = ODataAtomConvert.ToString((bool)value);
                break;

            case TypeCode.Byte:
                result = ODataAtomConvert.ToString((byte)value);
                break;

            case TypeCode.DateTime:
                result = ODataAtomConvert.ToString((DateTime)value);
                break;

            case TypeCode.Decimal:
                result = ODataAtomConvert.ToString((decimal)value);
                break;

            case TypeCode.Double:
                result = ODataAtomConvert.ToString((double)value);
                break;

            case TypeCode.Int16:
                result = ODataAtomConvert.ToString((Int16)value);
                break;

            case TypeCode.Int32:
                result = ODataAtomConvert.ToString((Int32)value);
                break;

            case TypeCode.Int64:
                result = ODataAtomConvert.ToString((Int64)value);
                break;

            case TypeCode.SByte:
                result = ODataAtomConvert.ToString((SByte)value);
                break;

            case TypeCode.String:
                result             = (string)value;
                preserveWhitespace = true;
                break;

            case TypeCode.Single:
                result = ODataAtomConvert.ToString((Single)value);
                break;

            default:
                byte[] bytes = value as byte[];
                if (bytes != null)
                {
                    result = ODataAtomConvert.ToString(bytes);
                    break;
                }

                if (value is DateTimeOffset)
                {
                    result = ODataAtomConvert.ToString((DateTimeOffset)value);
                    break;
                }

                if (value is Guid)
                {
                    result = ODataAtomConvert.ToString((Guid)value);
                    break;
                }

                if (value is TimeSpan)
                {
                    // Edm.Time
                    result = ODataAtomConvert.ToString((TimeSpan)value);
                    break;
                }

                return(false);
            }

            Debug.Assert(result != null, "result != null");
            return(true);
        }
예제 #5
0
        /// <summary>
        /// Enumerates each charset part in the specified Accept-Charset header.
        /// </summary>
        /// <param name="headerValue">Non-null and non-empty header value for Accept-Charset.</param>
        /// <returns>
        /// A (non-sorted) enumeration of CharsetPart elements, which include
        /// a charset name and a quality (preference) value, normalized to 0-1000.
        /// </returns>
        private static IEnumerable <CharsetPart> AcceptCharsetParts(string headerValue)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(!String.IsNullOrEmpty(headerValue), "!String.IsNullOrEmpty(headerValuer)");

            // PERF: optimize for common patterns.
            bool commaRequired = false; // Whether a comma should be found
            int  headerIndex   = 0;     // Index of character being procesed on headerValue.
            int  headerStart;           // Index into headerValue for the start of the charset name.
            int  headerNameEnd;         // Index into headerValue for the end of the charset name (+1).
            int  headerEnd;             // Index into headerValue for this charset part (+1).
            int  qualityValue;          // Normalized qvalue for this charset.

            while (headerIndex < headerValue.Length)
            {
                if (SkipWhitespace(headerValue, ref headerIndex))
                {
                    yield break;
                }

                if (headerValue[headerIndex] == ',')
                {
                    commaRequired = false;
                    headerIndex++;
                    continue;
                }

                if (commaRequired)
                {
                    // Comma missing between charset elements.
                    throw new ODataException(Strings.HttpUtils_MissingSeparatorBetweenCharsets(headerValue));
                }

                headerStart   = headerIndex;
                headerNameEnd = headerStart;

                bool endReached = ReadToken(headerValue, ref headerNameEnd);
                if (headerNameEnd == headerIndex)
                {
                    // Invalid (empty) charset name.
                    throw new ODataException(Strings.HttpUtils_InvalidCharsetName(headerValue));
                }

                if (endReached)
                {
                    qualityValue = 1000;
                    headerEnd    = headerNameEnd;
                }
                else
                {
                    char afterNameChar = headerValue[headerNameEnd];
                    if (IsHttpSeparator(afterNameChar))
                    {
                        if (afterNameChar == ';')
                        {
                            if (ReadLiteral(headerValue, headerNameEnd, ";q="))
                            {
                                // Unexpected end of qvalue.
                                throw new ODataException(Strings.HttpUtils_UnexpectedEndOfQValue(headerValue));
                            }

                            headerEnd = headerNameEnd + 3;
                            ReadQualityValue(headerValue, ref headerEnd, out qualityValue);
                        }
                        else
                        {
                            qualityValue = 1000;
                            headerEnd    = headerNameEnd;
                        }
                    }
                    else
                    {
                        // Invalid separator character.
                        throw new ODataException(Strings.HttpUtils_InvalidSeparatorBetweenCharsets(headerValue));
                    }
                }

                yield return(new CharsetPart(headerValue.Substring(headerStart, headerNameEnd - headerStart), qualityValue));

                // Prepare for next charset; we require at least one comma before we process it.
                commaRequired = true;
                headerIndex   = headerEnd;
            }
        }
예제 #6
0
        /// <summary>
        /// Parses query options from a specified URI into a dictionary.
        /// </summary>
        /// <param name="uri">The uri to get the query options from.</param>
        /// <returns>The parsed query options.</returns>
        /// <remarks>This method returns <see cref="List&lt;QueryOptionQueryToken&gt;"/> with all the query options.
        /// Note that it is valid to include multiple query options with the same name.</remarks>
        internal static List <QueryOptionQueryToken> ParseQueryOptions(Uri uri)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(uri != null, "uri != null");

            List <QueryOptionQueryToken> queryOptions = new List <QueryOptionQueryToken>();

            string queryString = uri.Query;
            int    length;

            if (queryString != null)
            {
                if (queryString.Length > 0 && queryString[0] == '?')
                {
                    queryString = queryString.Substring(1);
                }

                length = queryString.Length;
            }
            else
            {
                length = 0;
            }

            for (int i = 0; i < length; i++)
            {
                int startIndex     = i;
                int equalSignIndex = -1;
                while (i < length)
                {
                    char ch = queryString[i];
                    if (ch == '=')
                    {
                        if (equalSignIndex < 0)
                        {
                            equalSignIndex = i;
                        }
                    }
                    else if (ch == '&')
                    {
                        break;
                    }

                    i++;
                }

                string queryOptionsName = null;
                string queryOptionValue = null;
                if (equalSignIndex >= 0)
                {
                    queryOptionsName = queryString.Substring(startIndex, equalSignIndex - startIndex);
                    queryOptionValue = queryString.Substring(equalSignIndex + 1, (i - equalSignIndex) - 1);
                }
                else
                {
                    queryOptionValue = queryString.Substring(startIndex, i - startIndex);
                }

                queryOptionsName = queryOptionsName == null ? null : Uri.UnescapeDataString(queryOptionsName);
                queryOptionValue = queryOptionValue == null ? null : Uri.UnescapeDataString(queryOptionValue);

                queryOptions.Add(new QueryOptionQueryToken {
                    Name = queryOptionsName, Value = queryOptionValue
                });

                if ((i == (length - 1)) && (queryString[i] == '&'))
                {
                    queryOptions.Add(new QueryOptionQueryToken {
                        Name = null, Value = string.Empty
                    });
                }
            }

            return(queryOptions);
        }
예제 #7
0
        internal static string GetStatusMessage(int statusCode)
        {
            DebugUtils.CheckNoExternalCallers();

            // Non-localized messages for status codes.
            // These are the recommended reason phrases as per HTTP RFC 2616, Section 6.1.1
            switch (statusCode)
            {
            case 100:
                return("Continue");

            case 101:
                return("Switching Protocols");

            case 200:
                return("OK");

            case 201:
                return("Created");

            case 202:
                return("Accepted");

            case 203:
                return("Non-Authoritative Information");

            case 204:
                return("No Content");

            case 205:
                return("Reset Content");

            case 206:
                return("Partial Content");

            case 300:
                return("Multiple Choices");

            case 301:
                return("Moved Permanently");

            case 302:
                return("Found");

            case 303:
                return("See Other");

            case 304:
                return("Not Modified");

            case 305:
                return("Use Proxy");

            case 307:
                return("Temporary Redirect");

            case 400:
                return("Bad Request");

            case 401:
                return("Unauthorized");

            case 402:
                return("Payment Required");

            case 403:
                return("Forbidden");

            case 404:
                return("Not Found");

            case 405:
                return("Method Not Allowed");

            case 406:
                return("Not Acceptable");

            case 407:
                return("Proxy Authentication Required");

            case 408:
                return("Request Time-out");

            case 409:
                return("Conflict");

            case 410:
                return("Gone");

            case 411:
                return("Length Required");

            case 412:
                return("Precondition Failed");

            case 413:
                return("Request Entity Too Large");

            case 414:
                return("Request-URI Too Large");

            case 415:
                return("Unsupported Media Type");

            case 416:
                return("Requested range not satisfiable");

            case 417:
                return("Expectation Failed");

            case 500:
                return("Internal Server Error");

            case 501:
                return("Not Implemented");

            case 502:
                return("Bad Gateway");

            case 503:
                return("Service Unavailable");

            case 504:
                return("Gateway Time-out");

            case 505:
                return("HTTP Version not supported");

            default:
                return("Unknown Status Code");
            }
        }
예제 #8
0
        /// <summary>
        /// Does an ordinal ignore case comparision of the given media type names.
        /// </summary>
        /// <param name="mediaTypeName1">First media type name.</param>
        /// <param name="mediaTypeName2">Second media type name.</param>
        /// <returns>returns true if the media type names are the same.</returns>
        internal static bool CompareMediaTypeNames(string mediaTypeName1, string mediaTypeName2)
        {
            DebugUtils.CheckNoExternalCallers();

            return(String.Equals(mediaTypeName1, mediaTypeName2, StringComparison.OrdinalIgnoreCase));
        }
 /// <summary>
 /// Indicates that the headers and request/response line have been written.
 /// Can be called only once per batch message and headers cannot be modified
 /// anymore after this method was called.
 /// </summary>
 internal void WriteMessageDataCompleted()
 {
     DebugUtils.CheckNoExternalCallers();
     this.outputStream = null;
 }
        /// <summary>
        /// Constructor. Creates a request message for an operation of a batch response.
        /// </summary>
        /// <param name="outputStream">The underlying stream to write the message to.</param>
        /// <param name="operationListener">Listener interface to be notified of operation changes.</param>
        internal ODataBatchOperationResponseMessage(Stream outputStream, IODataBatchOperationListener operationListener)
        {
            DebugUtils.CheckNoExternalCallers();

            this.message = new ODataBatchOperationMessage(outputStream, operationListener);
        }
예제 #11
0
 /// <summary>
 /// Initializes a new <see cref="MediaType"/> read-only instance.
 /// </summary>
 /// <param name="type">Type specification (for example, 'text').</param>
 /// <param name="subType">Sub-type specification (for example, 'plain').</param>
 /// <param name="parameter">A single parameter specified on the media type.</param>
 internal MediaType(string type, string subType, KeyValuePair <string, string> parameter)
     : this(type, subType, new KeyValuePair <string, string>[] { parameter })
 {
     DebugUtils.CheckNoExternalCallers();
 }
예제 #12
0
 /// <summary>
 /// Initializes a new <see cref="MediaType"/> read-only instance.
 /// </summary>
 /// <param name="type">Type specification (for example, 'text').</param>
 /// <param name="subType">Sub-type specification (for example, 'plain').</param>
 internal MediaType(string type, string subType)
     : this(type, subType, (IList <KeyValuePair <string, string> >)null)
 {
     DebugUtils.CheckNoExternalCallers();
 }
예제 #13
0
        /// <summary>
        /// Gets a number of non-* matching type name parts and parameters; returns the number of matching type name parts or -1 if not matching at all.
        /// The <paramref name="matchingParameters"/> represent the number of matched parameters or -1 if there are no parameters to match and the candidate
        /// type also has no parameters.
        /// </summary>
        /// <param name="candidate">Candidate media type to match.</param>
        /// <param name="matchingParameters">The number of matched parameters or -1 if there are no parameters to match and the <paramref name="candidate"/> does not have parameters either.</param>
        /// <param name="qualityValue">The quality value of the candidate (or -1 if none is specified).</param>
        /// <param name="parameterCount">The number of parameters of this type that are not accept-parameters (and thus ignored).</param>
        /// <returns>Returns the number of matching type name parts or -1 if not matching at all. The <paramref name="matchingParameters"/>
        /// represent the number of matched parameters or -1 if there are no parameters to match and the candidate
        /// type also has no parameters.
        /// </returns>
        internal int GetMatchingParts(MediaType candidate, out int matchingParameters, out int qualityValue, out int parameterCount)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(candidate != null, "candidate must not be null.");

            int matchedNameParts = -1;

            if (this.type == "*")
            {
                matchedNameParts = 0;
            }
            else
            {
                if (HttpUtils.CompareMediaTypeNames(this.type, candidate.type))
                {
                    if (this.subType == "*")
                    {
                        // only type matches
                        matchedNameParts = 1;
                    }
                    else if (HttpUtils.CompareMediaTypeNames(this.subType, candidate.subType))
                    {
                        // both type and subtype match
                        matchedNameParts = 2;
                    }
                }
            }

            qualityValue       = DefaultQualityValue;
            parameterCount     = 0;
            matchingParameters = 0;

            // NOTE: we know that the candidates don't have accept parameters so we can rely
            //       on the total parameter count.
            IList <KeyValuePair <string, string> > candidateParameters = candidate.Parameters;
            bool candidateHasParams = candidateParameters != null && candidateParameters.Count > 0;
            bool thisHasParams      = this.parameters != null && this.parameters.Count > 0;

            if (thisHasParams)
            {
                for (int i = 0; i < this.parameters.Count; ++i)
                {
                    string parameterName = this.parameters[i].Key;
                    if (IsQualityValueParameter(parameterName))
                    {
                        // once we hit the q-value in the parameters we know that only accept-params will follow
                        // that don't contribute to the matching. Parse the quality value but don't continue processing
                        // parameters.
                        qualityValue = ParseQualityValue(this.parameters[i].Value.Trim());
                        break;
                    }

                    parameterCount = i + 1;

                    if (candidateHasParams)
                    {
                        // find the current parameter name in the set of parameters of the candidate and compare the value;
                        // if they match increase the result count
                        string parameterValue;
                        if (TryFindMediaTypeParameter(candidateParameters, parameterName, out parameterValue) &&
                            string.Compare(this.parameters[i].Value.Trim(), parameterValue.Trim(), StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            matchingParameters++;
                        }
                    }
                }
            }

            // if we have no non-accept parameters special rules apply
            if (!thisHasParams || parameterCount == 0)
            {
                if (candidateHasParams)
                {
                    if (matchedNameParts == 0 || matchedNameParts == 1)
                    {
                        // this is a media range specification using the '*' wildcard.
                        // we assume that all parameters are matched for such ranges so the server
                        // will pick the most specific one
                        matchingParameters = candidateParameters.Count;
                    }
                    else
                    {
                        // the candidate type has parameters while this type has not;
                        // return 0 to indicate that none of the candidate's parameters match.
                        matchingParameters = 0;
                    }
                }
                else
                {
                    // neither this type nor the candidate have parameters; in this case we return -1 to indicate
                    // that the candidate parameters are a perfect.
                    matchingParameters = -1;
                }
            }

            return(matchedNameParts);
        }
예제 #14
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="stream">The underlying async stream to wrap. Note that only asynchronous write operation will be invoked on this stream.</param>
 internal AsyncBufferedStream(Stream stream)
     : this(stream, false)
 {
     DebugUtils.CheckNoExternalCallers();
 }
예제 #15
0
 /// <summary>
 /// Sets the value of an HTTP header.
 /// </summary>
 /// <param name="headerName">The name of the header to set.</param>
 /// <param name="headerValue">The value of the HTTP header or 'null' if the header should be removed.</param>
 internal override void SetHeader(string headerName, string headerValue)
 {
     DebugUtils.CheckNoExternalCallers();
     this.requestMessage.SetHeader(headerName, headerValue);
 }
예제 #16
0
        /// <summary>
        /// Try to determine the primitive type of the <paramref name="value"/> argument and return the name of the primitive type.
        /// </summary>
        /// <param name="value">The value to determine the type for.</param>
        /// <param name="typeName">The name of the primitive type of the <paramref name="value"/>.</param>
        /// <returns>True if the value is of a known primitive type; otherwise false.</returns>
        internal static bool TryGetPrimitiveTypeName(object value, out string typeName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(value != null, "value != null");

            typeName = null;

            TypeCode typeCode = Type.GetTypeCode(value.GetType());

            switch (typeCode)
            {
            case TypeCode.Boolean:
                typeName = EdmConstants.EdmBooleanTypeName;
                break;

            case TypeCode.Byte:
                typeName = EdmConstants.EdmByteTypeName;
                break;

            case TypeCode.DateTime:
                typeName = EdmConstants.EdmDateTimeTypeName;
                break;

            case TypeCode.Decimal:
                typeName = EdmConstants.EdmDecimalTypeName;
                break;

            case TypeCode.Double:
                typeName = EdmConstants.EdmDoubleTypeName;
                break;

            case TypeCode.Int16:
                typeName = EdmConstants.EdmInt16TypeName;
                break;

            case TypeCode.Int32:
                typeName = EdmConstants.EdmInt32TypeName;
                break;

            case TypeCode.Int64:
                typeName = EdmConstants.EdmInt64TypeName;
                break;

            case TypeCode.SByte:
                typeName = EdmConstants.EdmSByteTypeName;
                break;

            case TypeCode.String:
                typeName = EdmConstants.EdmStringTypeName;
                break;

            case TypeCode.Single:
                typeName = EdmConstants.EdmSingleTypeName;
                break;

            default:
                byte[] bytes = value as byte[];
                if (bytes != null)
                {
                    typeName = EdmConstants.EdmBinaryTypeName;
                    break;
                }

                if (value is DateTimeOffset)
                {
                    typeName = EdmConstants.EdmDateTimeOffsetTypeName;
                    break;
                }

                if (value is Guid)
                {
                    typeName = EdmConstants.EdmGuidTypeName;
                    break;
                }

                if (value is TimeSpan)
                {
                    // Edm.Time
                    typeName = EdmConstants.EdmTimeTypeName;
                    break;
                }

                return(false);
            }

            Debug.Assert(typeName != null, "typeName != null");
            return(true);
        }
 /// <summary>
 /// Returns true if the specified kind enum has the specified flags set.
 /// </summary>
 /// <param name="kind">The kind enum to test.</param>
 /// <param name="flag">The flag to look for.</param>
 /// <returns>true if the flag is set; false otherwise.</returns>
 internal static bool HasFlag(this ODataResourcePropertyKind kind, ODataResourcePropertyKind flag)
 {
     DebugUtils.CheckNoExternalCallers();
     return((kind & flag) == flag);
 }
예제 #18
0
 /// <summary>
 /// Constructs a new ODataMessage.
 /// </summary>
 protected ODataMessage()
 {
     DebugUtils.CheckNoExternalCallers();
 }