HostedHttpRequestAsyncResult.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Activation / HostedHttpRequestAsyncResult.cs / 3 / HostedHttpRequestAsyncResult.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Activation
{ 
    using System.Diagnostics;
    using System.Globalization; 
    using System.Net; 
    using System.Text;
    using System.Threading; 
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Diagnostics;
    using System.Web; 
    using System.Web.Hosting;
    using System.Web.Compilation; 
    using System.Security.Principal; 
    using System.IO;
    using System.Security; 
    using System.Security.Permissions;

    class HostedHttpRequestAsyncResult : AsyncResult
    { 

        ///  
        /// Critical - stores the securitycritical callback values 
        ///            we need to protect these value
       ///  
        [SecurityCritical]
        static WindowsIdentity anonymousIdentity;
        [SecurityCritical]
        static WaitCallback waitOnBeginRequest; 
        [SecurityCritical]
        static WaitCallback waitOnBeginRequestWithFlow; 
        [SecurityCritical] 
        static ContextCallback contextOnBeginRequest;
        [SecurityCritical] 
        static AsyncCallback processRequestCompleteCallback;


        [ThreadStatic] 
        static AutoResetEvent waitObject;
 
 
        /// 
        /// Critical - keeps track of impersonated user, caller must use with care 
        /// 
        [SecurityCritical]
        HostedImpersonationContext impersonationContext;
 
        /// 
        /// Critical - keeps track of thread static data (HttpContext, CurrentCulture, CurrentUICulture) that 
        ///            is used for AspNetCompatibility mode, caller must use with care 
        /// 
        [SecurityCritical] 
        HostedThreadData hostedThreadData;

        /// 
        /// Critical - this field is used to manipulate request/responses using APIs protected by LinkDemand 
        ///            it is critical because we use it to determine whether we believe we're being hosted in ASP.NET or not
        ///            the field is set in the constructor of this class and we deem it safe because: 
        ///             1) all paths that lead to the .ctor are SecurityCritical and 
        ///             2) those paths have called ServiceHostingEnvironment.EnsureInitialized (which is also critical)
        ///            so if the field is not null, it's safe to say that we're hosted in ASP.NET, 
        ///            hence all the helper methods in this class that touch this field can be SecurityTreatAsSafe
        /// 
        [SecurityCritical]
        HttpApplication context; 

        Uri originalRequestUri; 
        Uri requestUri; 
        int state;
 
        /// 
        /// Critical - Determines whether to set the HttpContext on the outgoing thread.
        /// 
        [SecurityCritical] 
        bool flowContext;
 
        static class State 
        {
            internal const int Running   = 0; 
            internal const int Completed = 1;
            internal const int Aborted   = 2;
        }
 
        /// 
        /// Critical & TreatAsSafe - Mark this property as Securitycritical and SecuritytreatasSafe 
        /// in order access the value of corresponding static field and prevent someone form changing its value 
        /// 
        public static WindowsIdentity AnonymousIdentity 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                if (null == anonymousIdentity)
                { 
                    anonymousIdentity = WindowsIdentity.GetAnonymous(); 
                }
                return anonymousIdentity; 
            }
        }

        ///  
        /// Critical & TreatAsSafe - Mark this property as Securitycritical and SecuritytreatasSafe
        /// in order access the value of corresponding static field and prevent someone form changing its value 
        ///  
        public static WaitCallback WaitOnBeginRequest
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                if (null == waitOnBeginRequest) 
                {
                    waitOnBeginRequest = new WaitCallback(OnBeginRequest); 
                } 
                return waitOnBeginRequest;
            } 
        }

        /// 
        /// Critical & TreatAsSafe - Mark this property as Securitycritical and Securitytreatassafe 
        /// in order access the value of corresponding static field and prevent someone form changing its value
        ///  
        public static WaitCallback WaitOnBeginRequestWithFlow 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {

                if (null == waitOnBeginRequestWithFlow) 
                {
                    waitOnBeginRequestWithFlow = new WaitCallback(OnBeginRequestWithFlow); 
                } 
                return waitOnBeginRequestWithFlow;
            } 
        }

        /// 
        /// Critical & TreatAsSafe - Mark this property as Securitycritical and SecuritytreatasSafe 
        /// in order access the value of corresponding static field and prevent someone form changing its value
        ///  
        public static ContextCallback ContextOnBeginRequest 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                if (null == contextOnBeginRequest)
                { 
                    contextOnBeginRequest = new ContextCallback(OnBeginRequest);
                } 
                return contextOnBeginRequest; 
            }
        } 


        /// 
        /// Critical & TreatAsSafe - Mark this property as Securitycritical and SecuritytreatasSafe 
        /// in order access the value of corresponding static field and prevent someone form changing its value
        ///  
        public static AsyncCallback ProcessRequestCompleteCallback 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                if (null == processRequestCompleteCallback)
                { 
                    processRequestCompleteCallback = DiagnosticUtility.Utility.ThunkCallback(new AsyncCallback(ProcessRequestComplete));
                } 
                return processRequestCompleteCallback; 
            }
        } 


        /// 
        /// Critical - Captures HostedImpersonationContext which must be done in the right place, and calls unsafe 
        ///            ScheduleCallbackLowPriNoFlow and ScriptTimeout.  Called outside of user security context.
        ///            callers of this .ctor must call ServiceHostingEnvironment.EnsureInitialized 
        ///  
        [SecurityCritical]
        public static void ExecuteSynchronous(HttpApplication context, bool flowContext) 
        {
            AutoResetEvent wait = HostedHttpRequestAsyncResult.waitObject;
            if (wait == null)
            { 
                wait = new AutoResetEvent(false);
                HostedHttpRequestAsyncResult.waitObject = wait; 
            } 

            HostedHttpRequestAsyncResult result; 
            try
            {
                result = new HostedHttpRequestAsyncResult(context, flowContext, ProcessRequestCompleteCallback, wait);
                if (!result.CompletedSynchronously) 
                {
                    wait.WaitOne(); 
                } 
                wait = null;
            } 
            finally
            {
                if (wait != null)
                { 
                    // Not sure of the state anymore.
                    HostedHttpRequestAsyncResult.waitObject = null; 
                    wait.Close(); 
                }
            } 

            HostedHttpRequestAsyncResult.End(result);
        }
 
        /// 
        /// Review - Can be called outside of a user context. 
        ///  
        [SecurityRequiresReview]
        static void ProcessRequestComplete(IAsyncResult result) 
        {
            if (!result.CompletedSynchronously)
            {
                try 
                {
                    ((AutoResetEvent) result.AsyncState).Set(); 
                } 
                catch (ObjectDisposedException exception)
                { 
                    if (DiagnosticUtility.ShouldTraceWarning)
                    {
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning);
                    } 
                }
            } 
        } 

        ///  
        /// Critical - Captures HostedImpersonationContext which must be done in the right place, and calls unsafe
        ///            ScheduleCallbackLowPriNoFlow and ScriptTimeout.  Called outside of user security context.
        /// 
        [SecurityCritical] 
        public HostedHttpRequestAsyncResult(HttpApplication context, bool flowContext, AsyncCallback callback, object state) :
            base(callback, state) 
        { 
            if (context == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("context")); 

            this.context = context;
            this.flowContext = flowContext;
 
            // If this is a DEBUG request, complete right away and let ASP.NET handle it.
            string method = context.Request.HttpMethod ?? ""; 
            char firstMethodChar = method.Length == 5 ? method[0] : '\0'; 
            if ((firstMethodChar == 'd' || firstMethodChar == 'D') &&
                string.Compare(method, "DEBUG", StringComparison.OrdinalIgnoreCase) == 0) 
            {
                if (DiagnosticUtility.ShouldTraceVerbose)
                {
                    TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.WebHostDebugRequest, this); 
                }
 
                this.state = State.Completed; 
                Complete(true, null);
                return; 
            }

            this.impersonationContext = new HostedImpersonationContext();
 
            if (flowContext)
            { 
                if (ServiceHostingEnvironment.AspNetCompatibilityEnabled) 
                {
                    // Capture HttpContext/culture context if necessary.  Can be used later by HostedHttpInput to re-apply 
                    // the culture during dispatch.  Also flowed here.
                    hostedThreadData = new HostedThreadData();
                }
            } 

            // Set this up before calling IncrementRequestCount so if it fails, we don't leak a count. 
            WaitCallback iotsCallback = (PartialTrustHelpers.NeedPartialTrustInvoke || flowContext) ? 
                WaitOnBeginRequestWithFlow : WaitOnBeginRequest;
 
            // Tell ASPNET to by-pass all the other events so no other http modules will
            // be invoked, Indigo basically takes over the request completely. This should
            // only be called in non-AspNetCompatibilityEnabled mode.
            if (!ServiceHostingEnvironment.AspNetCompatibilityEnabled) 
            {
                context.CompleteRequest(); 
            } 

            // Prevent ASP.NET from generating thread aborts in relation to this request. 
            context.Server.ScriptTimeout = int.MaxValue;

            ServiceHostingEnvironment.IncrementRequestCount();
 
            IOThreadScheduler.ScheduleCallbackLowPriNoFlow(iotsCallback, this);
        } 
 
        /// 
        /// Critical - can be called outside of user context, accesses hostedThreadData. 
        /// Safe - Uses hostedThreadData to set HttpContext.Current, cultures to the one attached to this async-result instance.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        static void OnBeginRequestWithFlow(object state) 
        {
            HostedHttpRequestAsyncResult self = (HostedHttpRequestAsyncResult) state; 
 
            IDisposable hostedThreadContext = null;
            try 
            {
                if (self.flowContext)
                {
                    // In AspCompat case, these are the three things that need to be flowed.  See HostedHttpInput. 
                    if (self.hostedThreadData != null)
                        hostedThreadContext = self.hostedThreadData.CreateContext(); 
                } 

                // In full-trust, this simply calls the delegate. 
                PartialTrustHelpers.PartialTrustInvoke(ContextOnBeginRequest, self);
            }
            finally
            { 
                if (hostedThreadContext != null)
                { 
                    hostedThreadContext.Dispose(); 
                }
            } 
        }

        static void OnBeginRequest(object state)
        { 
            HostedHttpRequestAsyncResult self = (HostedHttpRequestAsyncResult) state;
 
            Exception completionException = null; 
            try
            { 
                self.BeginRequest();
            }
            catch (Exception e)
            { 
                if (DiagnosticUtility.IsFatal(e))
                { 
                    throw; 
                }
 
                completionException = e;
            }

            if (completionException != null) 
            {
                self.CompleteOperation(completionException); 
            } 
        }
 
        void BeginRequest()
        {
            try
            { 
                HandleRequest();
            } 
            catch (EndpointNotFoundException exception) 
            {
                if (string.Compare(GetHttpMethod(), "GET", StringComparison.OrdinalIgnoreCase) == 0) 
                {
                    // Wrap the exception into HttpException.
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new HttpException((int)HttpStatusCode.NotFound, exception.Message, exception));
                } 

                SetStatusCode((int) HttpStatusCode.NotFound); 
                CompleteOperation(null); 
            }
            catch (ServiceActivationException exception) 
            {
                if (string.Compare(GetHttpMethod(), "GET", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    if (exception.InnerException is HttpException) 
                    {
                        throw exception.InnerException; 
                    } 
                    else
                    { 
                        throw;
                    }
                }
 
                SetStatusCode((int) HttpStatusCode.InternalServerError);
                SetStatusDescription( 
                    HttpChannelUtilities.StatusDescriptionStrings.HttpStatusServiceActivationException); 
                CompleteOperation(null);
            } 
            finally
            {
                ReleaseImpersonation();
            } 
        }
 
        public WindowsIdentity LogonUserIdentity 
        {
            get 
            {
                if (this.Application.User.Identity is WindowsIdentity)
                {
                    return (WindowsIdentity)this.Application.User.Identity; 
                }
                return AnonymousIdentity; 
            } 
        }
 
        public HostedImpersonationContext ImpersonationContext
        {
            /// 
            /// Critical - keeps track of impersonated user, caller must use with care 
            /// Safe - safe for Get, individual members of HostedImpersonationContext are protected
            ///  
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                return impersonationContext;
            }
        }
 
        public HostedThreadData HostedThreadData
        { 
            ///  
            /// Critical - keeps track of impersonated user, caller must use with care
            /// Safe - safe for Get, individual members of HostedThreadData are protected 
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                return hostedThreadData;
            } 
        } 

        public Uri OriginalRequestUri 
        {
            get
            {
                return this.originalRequestUri; 
            }
        } 
 
        public Uri RequestUri
        { 
            get
            {
                return this.requestUri;
            } 
        }
 
        public HttpApplication Application 
        {
            ///  
            /// Critical - touches critical field context
            /// Safe - does not leak control or data, no potential for harm
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                return this.context; 
            }
        } 

        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects
        /// Safe - does not leak control or data, no potential for harm 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public Stream GetInputStream() 
        {
            try 
            {
                return this.context.Request.InputStream;
            }
            catch (HttpException hostedException) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(hostedException.Message, hostedException)); 
            } 
        }
 
        public void OnReplySent()
        {
            CompleteOperation(null);
        } 

        void CompleteOperation(Exception exception) 
        { 
            if (this.state == State.Running &&
                Interlocked.CompareExchange(ref this.state, State.Completed, State.Running) == State.Running) 
            {
                Complete(false, exception);
                ServiceHostingEnvironment.DecrementRequestCount();
            } 
        }
 
        public void Abort() 
        {
            if (this.state == State.Running && 
                Interlocked.CompareExchange(ref this.state, State.Aborted, State.Running) == State.Running)
            {
                // Closes the socket connection to the client
                Application.Response.Close(); 

                Complete(false, null); 
                ServiceHostingEnvironment.DecrementRequestCount(); 
            }
        } 

        /// 
        /// Review - can be called outside of user context.
        ///  
        [SecurityRequiresReview]
        public static void End(IAsyncResult result) 
        { 
            if (result == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("result")); 

            try
            {
                AsyncResult.End(result); 
            }
            catch (Exception exception) 
            { 
                if (!(DiagnosticUtility.IsFatal(exception)))
                { 
                    // Log the exception.
                    DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostFailedToProcessRequest,
                      DiagnosticTrace.CreateSourceString(result),
                      exception == null ? string.Empty : exception.ToString()); 
                }
                throw; 
            } 
        }
 
        void HandleRequest()
        {
            this.originalRequestUri = GetUrl();
 
            string relativeVirtualPath = GetAppRelativeCurrentExecutionFilePath();
 
            // Support for Cassini. 
            if (ServiceHostingEnvironment.IsSimpleApplicationHost)
            { 
                HostedTransportConfigurationManager.EnsureInitializedForSimpleApplicationHost(this);
            }

            HttpHostedTransportConfiguration transportConfiguration = HostedTransportConfigurationManager.GetConfiguration(this.originalRequestUri.Scheme) 
                as HttpHostedTransportConfiguration;
            HostedHttpTransportManager transportManager = null; 
 
            // There must be a transport binding that matches the request.
            if (transportConfiguration != null) 
            {
                transportManager = transportConfiguration.GetHttpTransportManager(this.originalRequestUri);
            }
 
            if (transportManager == null)
            { 
                InvalidOperationException invalidOpException = new InvalidOperationException(SR.GetString(SR.Hosting_TransportBindingNotFound, originalRequestUri.ToString())); 

                ServiceActivationException activationException = new ServiceActivationException(invalidOpException.Message, invalidOpException); 

                LogServiceActivationException(activationException);

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(activationException); 
            }
 
            this.requestUri = new Uri(transportManager.ListenUri, this.originalRequestUri.PathAndQuery); 
            DiagnosticUtility.DebugAssert(
                object.ReferenceEquals(requestUri.Scheme, Uri.UriSchemeHttp) || object.ReferenceEquals(requestUri.Scheme, Uri.UriSchemeHttps), 
                "Scheme must be Http or Https.");

            ServiceHostingEnvironment.EnsureServiceAvailableFast(relativeVirtualPath);
 
            transportManager.HttpContextReceived(this);
        } 
 
        /// 
        /// Critical - Calls into an unsafe UnsafeLogEvent method 
        /// TreatAsSafe - Event identities cannot be spoofed as they are constants determined inside the method
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void LogServiceActivationException(ServiceActivationException activationException) 
        {
            DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostFailedToProcessRequest, true, 
                    DiagnosticTrace.CreateSourceString(this), 
                    activationException == null ? string.Empty : activationException.ToString());
        } 

        /// 
        /// Critical - manipulates impersonation object
        /// Safe - Releasing the SafeHandle early could only cause a future impersonation attempt to fail.  We have to 
        ///        handle impersonation failures well already.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        void ReleaseImpersonation()
        { 
            if (this.impersonationContext != null)
            {
                this.impersonationContext.Release();
            } 
        }
 
        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response
        /// Safe - does not leak control or mutable/harmful data, no potential for harm 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void SetContentType(string contentType)
        { 
            this.context.Response.ContentType = contentType;
        } 
 

        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response
        /// Safe - does not leak control or mutable/harmful data, no potential for harm
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void SetTransferModeToStreaming()
        { 
            this.context.Response.BufferOutput = false; 
        }
 
        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response
        /// Safe - does not leak control or mutable/harmful data, no potential for harm
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal void AppendHeader(string name, string value) 
        { 
            this.context.Response.AppendHeader(name, value);
        } 

        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response
        /// Safe - does not leak control or mutable/harmful data, no potential for harm 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void SetStatusCode(int statusCode) 
        {
            this.context.Response.TrySkipIisCustomErrors = true; 
            this.context.Response.StatusCode = statusCode;
        }

        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response
        /// Safe - does not leak control or mutable/harmful data, no potential for harm 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal void SetStatusDescription(string statusDescription) 
        {
            this.context.Response.StatusDescription = statusDescription;
        }
 
        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response 
        /// Safe - does not leak control or data, no potential for harm 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void SetConnectionClose()
        {
            this.context.Response.AppendHeader("Connection", "close");
        } 

        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects 
        /// Safe - does not leak control or data, no potential for harm
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal byte[] GetPrereadBuffer(ref int contentLength)
        {
            byte[] preReadBuffer = new byte[1]; 
            if (this.GetInputStream().Read(preReadBuffer, 0, 1) > 0)
            { 
                contentLength = -1; 
                return preReadBuffer;
            } 
            return null;
        }

        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects
        /// Safe - does not leak control or data, no potential for harm 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal Stream GetOutputStream() 
        {
            return this.context.Response.OutputStream;
        }
 
        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects 
        /// Safe - does not leak control or mutable/harmful data, no potential for harm 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal string GetHttpMethod()
        {
            return this.context.Request.HttpMethod;
        } 

        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects 
        /// Safe - does not leak control or mutable/harmful data, no potential for harm
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal string GetContentType()
        {
            const string ContentTypeHeaderName = "Content-Type"; 
            return this.context.Request.Headers[ContentTypeHeaderName];
        } 
 
        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects 
        /// Safe - does not leak control or mutable/harmful data, no potential for harm
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal string GetContentTypeFast() 
        {
            return this.context.Request.ContentType; 
        } 

        ///  
        /// Critical - calls getters with LinkDemands in ASP .NET objects
        /// Safe - does not leak control or mutable/harmful data, no potential for harm
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal int GetContentLength()
        { 
            return this.context.Request.ContentLength; 
        }
 
        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects
        /// Safe - does not leak control or mutable/harmful data, no potential for harm
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal string GetSoapAction() 
        { 
            const string SoapActionHeaderName = "SOAPAction";
            return this.context.Request.Headers[SoapActionHeaderName]; 
        }

        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects 
        /// Safe - does not leak control of mutable/harmful data, no potential for harm
        [SecurityCritical, SecurityTreatAsSafe] 
        string GetAppRelativeCurrentExecutionFilePath() 
        {
            return this.context.Request.AppRelativeCurrentExecutionFilePath; 
        }

        /// 
        /// Critical - calls getters with LinkDemands in ASP .NET objects 
        /// Safe - does not leak control of mutable/harmful data, no potential for harm
        [SecurityCritical, SecurityTreatAsSafe] 
        Uri GetUrl() 
        {
            return this.context.Request.Url; 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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