/// <summary>
        /// Gets the $callback query parameter if present. Also performs some validation:
        /// We do not allow $callback to be present if the content-type for the response is going to be anythign but JSON or plain text.
        /// </summary>
        /// <param name="message">The request message.</param>
        /// <param name="format">The format we will write the reponse in.</param>
        /// <returns>Returns the name of the callback function $callback specifies, or null if there isn't one.</returns>
        internal static string HandleCallbackQueryOption(AstoriaRequestMessage message, ODataFormatWithParameters format)
        {
            var functionName = message.GetQueryStringItem(XmlConstants.HttpQueryStringCallback);

            if (functionName != null)
            {
                // The verb must be GET (not IsQuery(), GET specifically)
                if (message.HttpVerb != HttpVerbs.GET)
                {
                    throw new DataServiceException(400, Strings.CallbackQueryOptionHandler_GetRequestsOnly);
                }

                // If conneg didn't get a format, that means that there was some error that we will fail at later, or
                // it is going end up being a 204, 304, or something else with no body. For all of these cases we are OK
                // with 'pretending' that $callback was not there, since the other errors are probably more important than
                // ours, and in the non-error cases we really should not be throwing (think 204).
                if (format == null)
                {
                    return null;
                }

                // JSON and text/plain are the only things allowed with $callback
                if (format.Format != ODataFormat.Json && format.Format != ODataFormat.RawValue)
                {
                    throw new DataServiceException(400, Strings.CallbackQueryOptionHandler_UnsupportedContentType(format.Format.ToString()));
                }
            }

            return functionName;
        }
        public void ContentTypeIsFromHost()
        {
            const string contentType = "application/atom+xml";
            var host = new DataServiceHostSimulator { RequestContentType = contentType };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.ContentType.Should().Be(contentType);
        }
Beispiel #3
0
        public void GetAcceptableContentTypesShouldCallDelegate()
        {
            var contentTypeSelector = new AcceptableContentTypeSelectorSimulator();
            var host           = new DataServiceHostSimulator();
            var requestMessage = new AstoriaRequestMessage(host, contentTypeSelector);

            requestMessage.GetAcceptableContentTypes().Should().Be(AcceptableContentTypeSelectorSimulator.GetFormatReturnValue);
        }
Beispiel #4
0
        public void AbsoluteServiceUriFromHostShouldHaveTrailingSlashAppended()
        {
            var requestMessage = new AstoriaRequestMessage(new DataServiceHostSimulator {
                AbsoluteServiceUri = new Uri("http://temp.org")
            });

            requestMessage.AbsoluteServiceUri.Should().Be("http://temp.org/");
        }
        public void GetDollarFormatQueryItemShouldGetValueFromHostGetQueryStringItemMethod()
        {
            const string queryKey = "$format";
            const string queryValue = "custom";
            var host = new DataServiceHostSimulator { };
            host.SetQueryStringItem(queryKey, queryValue);
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetQueryStringItem(queryKey).Should().Be(queryValue);
        }
        public void GetQueryStringItemShouldGetComponentFromHostGetQueryStringItemMethod()
        {
            const string queryKey = "queryKey";
            const string queryValue = "queryValue";
            var host = new DataServiceHostSimulator { AbsoluteRequestUri = new Uri("http://www.service.com/there/is/not/even/a/query-string") };
            host.SetQueryStringItem(queryKey, queryValue);
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetQueryStringItem(queryKey).Should().Be(queryValue);
        }
 public void Init()
 {
     this.requestMessageWithDefaultUris = new AstoriaRequestMessage(new DataServiceHostSimulator { AbsoluteServiceUri = this.absoluteServiceUri, AbsoluteRequestUri = this.absoluteRequestUri });
     this.requestMessageWithQueryStrings = new AstoriaRequestMessage(
         new DataServiceHostSimulator
         {
             AbsoluteServiceUri = new Uri(this.absoluteServiceUri.OriginalString + "?originalServiceQueryString"),
             AbsoluteRequestUri = new Uri(this.absoluteRequestUri + "?originalRequestQueryString"),
         });
 }
Beispiel #8
0
        public void RequestAcceptCharSetIsFromHost()
        {
            const string value = "some_other_value";
            var          host  = new DataServiceHostSimulator {
                RequestAcceptCharSet = value
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetHeader("Accept-Charset").Should().Be(value);
        }
Beispiel #9
0
        public void RequestContentTypeIsFromHost()
        {
            const string value = "a-content-type";
            var          host  = new DataServiceHostSimulator {
                RequestContentType = value
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetHeader("Content-Type").Should().Be(value);
        }
Beispiel #10
0
        public void RequestIfNoneMatch()
        {
            const string value = "someguid";
            var          host  = new DataServiceHostSimulator {
                RequestIfNoneMatch = value
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetHeader("If-None-Match").Should().Be(value);
        }
Beispiel #11
0
        public void ContentTypeIsFromHost()
        {
            const string contentType = "application/atom+xml";
            var          host        = new DataServiceHostSimulator {
                RequestContentType = contentType
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.ContentType.Should().Be(contentType);
        }
Beispiel #12
0
        public void GetAcceptableFormatTypesAcceptHeaderIsFromHost()
        {
            const string value = "some_value";
            var          host  = new DataServiceHostSimulator {
                RequestAccept = value
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.InitializeRequestVersionHeaders(V4);
            requestMessage.GetAcceptableContentTypes().Should().Be(value);
        }
Beispiel #13
0
        public void AfterInitializeVerionFieldsAreSetToDefaults()
        {
            var host           = new DataServiceHostSimulator {
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.InitializeRequestVersionHeaders(V4);

            requestMessage.RequestVersion.Should().Be(V4);
            requestMessage.RequestMaxVersion.Should().Be(V4);
        }
Beispiel #14
0
        public void ProcessExceptionShouldCallHost()
        {
            var callbackInvoked = false;
            var host            = new DataServiceHostSimulator {
            };

            host.ProcessExceptionCallBack = args => callbackInvoked = true;
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.ProcessException(new HandleExceptionArgs(new Exception(), true, null, false));
            callbackInvoked.Should().BeTrue();
        }
Beispiel #15
0
 public void Init()
 {
     this.requestMessageWithDefaultUris = new AstoriaRequestMessage(new DataServiceHostSimulator {
         AbsoluteServiceUri = this.absoluteServiceUri, AbsoluteRequestUri = this.absoluteRequestUri
     });
     this.requestMessageWithQueryStrings = new AstoriaRequestMessage(
         new DataServiceHostSimulator
     {
         AbsoluteServiceUri = new Uri(this.absoluteServiceUri.OriginalString + "?originalServiceQueryString"),
         AbsoluteRequestUri = new Uri(this.absoluteRequestUri + "?originalRequestQueryString"),
     });
 }
Beispiel #16
0
        public void GetDollarFormatQueryItemShouldGetValueFromHostGetQueryStringItemMethod()
        {
            const string queryKey   = "$format";
            const string queryValue = "custom";
            var          host       = new DataServiceHostSimulator {
            };

            host.SetQueryStringItem(queryKey, queryValue);
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetQueryStringItem(queryKey).Should().Be(queryValue);
        }
Beispiel #17
0
        public void GetQueryStringItemShouldGetComponentFromHostGetQueryStringItemMethod()
        {
            const string queryKey   = "queryKey";
            const string queryValue = "queryValue";
            var          host       = new DataServiceHostSimulator {
                AbsoluteRequestUri = new Uri("http://www.service.com/there/is/not/even/a/query-string")
            };

            host.SetQueryStringItem(queryKey, queryValue);
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetQueryStringItem(queryKey).Should().Be(queryValue);
        }
Beispiel #18
0
        public void HttpVerbIsFromHost()
        {
            foreach (var verb in HttpVerbUtils.KnownVerbs)
            {
                var host = new DataServiceHostSimulator {
                    RequestHttpMethod = verb.ToString()
                };
                var requestMessage = new AstoriaRequestMessage(host);

                requestMessage.HttpVerb.Should().Be(verb);
                requestMessage.RequestHttpMethod.Should().Be(verb.ToString());
            }
        }
Beispiel #19
0
        public void RequestHeadersIsFromHost()
        {
            var value = new WebHeaderCollection {
                { "RequestVersion", "2.0" }, { "Accept", "json" }, { "Custom", "customValue" }
            };
            var host = new DataServiceHost2Simulator {
                RequestHeaders = value
            };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.RequestHeaders.Should().BeEquivalentTo(value);
            requestMessage.RequestHeaders["RequestVersion"] = "2.0";
            requestMessage.RequestHeaders["Accept"]         = "json";
            requestMessage.RequestHeaders["Custom"]         = "customValue";
        }
Beispiel #20
0
        /// <summary>
        /// Initializes a new instance of <see cref="ODataMessageReaderDeserializer"/>.
        /// </summary>
        /// <param name="update">true if we're reading an update operation; false if not.</param>
        /// <param name="dataService">Data service for which the deserializer will act.</param>
        /// <param name="tracker">Tracker to use for modifications.</param>
        /// <param name="requestDescription">The request description to use.</param>
        /// <param name="enableODataServerBehavior">If true, the message reader settings will use the ODataServer behavior;
        /// if false, the message reader settings will use the default behavior.</param>
        internal ODataMessageReaderDeserializer(bool update, IDataService dataService, UpdateTracker tracker, RequestDescription requestDescription, bool enableODataServerBehavior)
            : base(update, dataService, tracker, requestDescription)
        {
            AstoriaRequestMessage requestMessage = dataService.OperationContext.RequestMessage;

            // WCF DS needs to treat content type */* as ATOM payload, so check for it here and override the content type header
            if (ContentTypeUtil.CompareMimeType(requestMessage.ContentType, XmlConstants.MimeAny))
            {
                requestMessage.ContentType = XmlConstants.MimeApplicationAtom;
            }

            this.messageReader = new ODataMessageReader(
                requestMessage,
                WebUtil.CreateMessageReaderSettings(dataService, enableODataServerBehavior),
                dataService.Provider.GetMetadataProviderEdmModel());
        }
Beispiel #21
0
        /// <summary>
        /// Get the ETag header value from the request headers.
        /// </summary>
        /// <param name="operationContext">A reference to the context for the current operation.</param>
        /// <param name="etag">
        /// The etag value sent by the client (as the value of an If[-None-]Match header) as part of the HTTP request sent to the data service
        /// This parameter will be null if no If[-None-]Match header was present
        /// </param>
        /// <param name="checkETagForEquality">
        /// True if an value of the etag parameter was sent to the server as the value of an If-Match HTTP request header
        /// False if an value of the etag parameter was sent to the server as the value of an If-None-Match HTTP request header
        /// null if the HTTP request for the stream was not a conditional request
        /// </param>
        private static void GetETagFromHeaders(DataServiceOperationContext operationContext, out string etag, out bool?checkETagForEquality)
        {
            Debug.Assert(operationContext != null, "operationContext != null");
            Debug.Assert(operationContext.RequestMessage != null, "operationContext.RequestMessage != null");
            AstoriaRequestMessage host = operationContext.RequestMessage;

            Debug.Assert(string.IsNullOrEmpty(host.GetRequestIfMatchHeader()) || string.IsNullOrEmpty(host.GetRequestIfNoneMatchHeader()), "IfMatch and IfNoneMatch should not be both set.");

            if (string.IsNullOrEmpty(host.GetRequestIfMatchHeader()) && string.IsNullOrEmpty(host.GetRequestIfNoneMatchHeader()))
            {
                etag = null;
                checkETagForEquality = null;
            }
            else if (!string.IsNullOrEmpty(host.GetRequestIfMatchHeader()))
            {
                etag = host.GetRequestIfMatchHeader();
                checkETagForEquality = true;
            }
            else
            {
                etag = host.GetRequestIfNoneMatchHeader();
                checkETagForEquality = false;
            }
        }
        public void RequestAcceptCharSetIsFromHost()
        {
            const string value = "some_other_value";
            var host = new DataServiceHostSimulator { RequestAcceptCharSet = value };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetHeader("Accept-Charset").Should().Be(value);
        }
Beispiel #23
0
        /// <summary>Handles an exception when processing a batch response.</summary>
        /// <param name='service'>Data service doing the processing.</param>
        /// <param name="requestMessage">requestMessage holding information about the request that caused an error</param>
        /// <param name="responseMessage">responseMessage to which we need to write the exception message</param>
        /// <param name='exception'>Exception thrown.</param>
        /// <param name='batchWriter'>Output writer for the batch.</param>
        /// <param name="responseStream">Underlying response stream.</param>
        /// <param name="defaultResponseVersion">The data service version to use for response, if it cannot be computed from the requestMessage.</param>
        internal static void HandleBatchOperationError(IDataService service, AstoriaRequestMessage requestMessage, IODataResponseMessage responseMessage, Exception exception, ODataBatchWriter batchWriter, Stream responseStream, Version defaultResponseVersion)
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(exception != null, "exception != null");
            Debug.Assert(batchWriter != null, "batchWriter != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null");
            Debug.Assert(CommonUtil.IsCatchableExceptionType(exception), "CommonUtil.IsCatchableExceptionType(exception)");

            ErrorHandler handler = CreateHandler(service, requestMessage, exception, defaultResponseVersion);

            service.InternalHandleException(handler.exceptionArgs);

            if (requestMessage != null && responseMessage != null)
            {
                responseMessage.SetHeader(XmlConstants.HttpODataVersion, handler.responseVersion.ToString(2) + ";");
                requestMessage.ProcessException(handler.exceptionArgs);

                // if ProcessBenignException returns anything, we can safely not write to the stream.
                if (ProcessBenignException(exception, service) != null)
                {
                    return;
                }
            }

            if (requestMessage != null)
            {
                responseMessage = requestMessage.BatchServiceHost.GetOperationResponseMessage();
                WebUtil.SetResponseHeadersForBatchRequests(responseMessage, requestMessage.BatchServiceHost);
            }
            else
            {
                responseMessage = batchWriter.CreateOperationResponseMessage(null);
                responseMessage.StatusCode = handler.exceptionArgs.ResponseStatusCode;
            }

            MessageWriterBuilder messageWriterBuilder = MessageWriterBuilder.ForError(
                null,
                service, 
                handler.responseVersion,
                responseMessage,
                handler.contentType,
                null /*acceptCharsetHeaderValue*/);
            using (ODataMessageWriter messageWriter = messageWriterBuilder.CreateWriter())
            {
                ODataError error = handler.exceptionArgs.CreateODataError();
                WriteErrorWithFallbackForXml(messageWriter, handler.encoding, responseStream, handler.exceptionArgs, error, messageWriterBuilder);
            }
        }
        public void GetAcceptableFormatTypesAcceptHeaderIsFromHost()
        {
            const string value = "some_value";
            var host = new DataServiceHostSimulator { RequestAccept = value };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.InitializeRequestVersionHeaders(V4);
            requestMessage.GetAcceptableContentTypes().Should().Be(value);
        }
        public void GetAcceptableContentTypesShouldCallDelegate()
        {
            var contentTypeSelector = new AcceptableContentTypeSelectorSimulator();
            var host = new DataServiceHostSimulator();
            var requestMessage = new AstoriaRequestMessage(host, contentTypeSelector);

            requestMessage.GetAcceptableContentTypes().Should().Be(AcceptableContentTypeSelectorSimulator.GetFormatReturnValue);
        }
 public void AbsoluteServiceUriFromHostShouldHaveTrailingSlashAppended()
 {
     var requestMessage = new AstoriaRequestMessage(new DataServiceHostSimulator { AbsoluteServiceUri = new Uri("http://temp.org") });
     requestMessage.AbsoluteServiceUri.Should().Be("http://temp.org/");
 }
        public void ProcessExceptionShouldCallHost()
        {
            var callbackInvoked = false;
            var host = new DataServiceHostSimulator { };
            host.ProcessExceptionCallBack = args => callbackInvoked = true;
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.ProcessException(new HandleExceptionArgs(new Exception(), true, null, false));
            callbackInvoked.Should().BeTrue();
        }
        public void HttpVerbIsFromHost()
        {
            foreach (var verb in HttpVerbUtils.KnownVerbs)
            {
                var host = new DataServiceHostSimulator { RequestHttpMethod = verb.ToString() };
                var requestMessage = new AstoriaRequestMessage(host);

                requestMessage.HttpVerb.Should().Be(verb);
                requestMessage.RequestHttpMethod.Should().Be(verb.ToString());
            }
        }
        public void RequestIfNoneMatch()
        {
            const string value = "someguid";
            var host = new DataServiceHostSimulator { RequestIfNoneMatch = value };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetHeader("If-None-Match").Should().Be(value);
        }
Beispiel #30
0
        private static ErrorHandler CreateHandler(IDataService service, AstoriaRequestMessage requestMessage, Exception exception, Version defaultResponseVersion)
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(service.Configuration != null, "service.Configuration != null");

            string acceptableContentTypes = null;
            string requestAcceptCharsetHeader = null;
            Version responseVersion = defaultResponseVersion;

            if (requestMessage != null)
            {
                acceptableContentTypes = requestMessage.GetAcceptableContentTypes();
                requestAcceptCharsetHeader = requestMessage.GetRequestAcceptCharsetHeader();

                try
                {
                    Version maxProtocolVersion = service.Configuration.DataServiceBehavior.MaxProtocolVersion.ToVersion();
                    requestMessage.InitializeRequestVersionHeaders(maxProtocolVersion);
                    responseVersion = VersionUtil.GetResponseVersionForError(requestMessage.GetAcceptableContentTypes(), requestMessage.RequestMaxVersion, maxProtocolVersion);
                }
                catch (Exception e)
                {
                    if (!CommonUtil.IsCatchableExceptionType(e))
                    {
                        throw;
                    }

                    // Ignore exceptions as we should use the default response version.
                }
            }

            return new ErrorHandler(exception, service.Configuration.UseVerboseErrors, responseVersion, acceptableContentTypes, requestAcceptCharsetHeader);
        }
        public void RequestHeadersIsFromHost()
        {
            var value = new WebHeaderCollection { { "RequestVersion", "2.0" }, { "Accept", "json" }, { "Custom", "customValue" } };
            var host = new DataServiceHost2Simulator { RequestHeaders = value };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.RequestHeaders.Should().BeEquivalentTo(value);
            requestMessage.RequestHeaders["RequestVersion"] = "2.0";
            requestMessage.RequestHeaders["Accept"] = "json";
            requestMessage.RequestHeaders["Custom"] = "customValue";
        }
        /// <summary>
        /// Creates a new instance of the RequestMessage and ResponseMessage to cache the request headers and to validate the data from the host interface.
        /// </summary>
        /// <remarks>
        /// Note that this code cannot go in the constructor, because it is possible for a user to attach a host to DataService,
        /// process a request, changes fields _on the same host_, and then call process request again. So we need to be able to 
        /// create a new AstoriaRequestMessage while still using the same DataServiceOpeationContext.
        /// </remarks>
        /// <param name="dataService">The current data service instance.</param>
        internal void InitializeAndCacheHeaders(IDataService dataService)
        {
            Debug.Assert(this.hostInterface != null, "this.hostInterface != null");

            this.requestMessage = new AstoriaRequestMessage(this.hostInterface);
            this.responseMessage = new AstoriaResponseMessage(this.hostInterface);

            this.CurrentDataService = dataService;

            // Add a "nosniff" content-type option to instruct IE8/9 not to sniff the content instead of rendering it
            // according to the specified content-type. This mitigates against XSS attacks such as embedded scripts in
            // content specified as text/plain.
            if (this.hostInterface is IDataServiceHost2)
            {
                this.ResponseHeaders.Add(XmlConstants.XContentTypeOptions, XmlConstants.XContentTypeOptionNoSniff);
            }
        }
        public void RequestContentTypeIsFromHost()
        {
            const string value = "a-content-type";
            var host = new DataServiceHostSimulator { RequestContentType = value };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.GetHeader("Content-Type").Should().Be(value);
        }
        public void AfterInitializeVerionFieldsAreSetWithHostValues()
        {
            var host = new DataServiceHostSimulator { RequestVersion = "4.0", RequestMaxVersion = "4.0" };
            var requestMessage = new AstoriaRequestMessage(host);

            requestMessage.InitializeRequestVersionHeaders(V4);

            requestMessage.RequestVersion.Should().Be(V4);
            requestMessage.RequestMaxVersion.Should().Be(V4);
        }
        /// <summary>
        /// Reads the parameters for the specified <paramref name="operation"/> from the <paramref name="host"/>.
        /// </summary>
        /// <param name="host">RequestMessage with request information.</param>
        /// <param name="operation">Operation with parameters to be read.</param>
        /// <returns>A new object[] with parameter values.</returns>
        private static object[] ReadOperationParameters(AstoriaRequestMessage host, OperationWrapper operation)
        {
            Debug.Assert(host != null, "host != null");
            Debug.Assert(operation != null, "operation != null");
            Debug.Assert(operation.Kind == OperationKind.ServiceOperation, "operation.Kind == OperationKind.ServiceOperation");

            object[] operationParameters = new object[operation.Parameters.Count];
            for (int i = 0; i < operation.Parameters.Count; i++)
            {
                Type parameterType = operation.Parameters[i].ParameterType.InstanceType;
                string queryStringValue = host.GetQueryStringItem(operation.Parameters[i].Name);
                operationParameters[i] = ParseOperationParameter(parameterType, queryStringValue);
            }

            return operationParameters;
        }