Commit 94582d28 authored by Jason Williams's avatar Jason Williams
Browse files

Fix CSRF retry logic to not retry with already disposed objects

parent 0e30f50b
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -379,6 +379,19 @@ namespace XboxWdpDriver
                    }
                }
            }
            catch (AggregateException e)
            {
                if (e.InnerException is DevicePortalException)
                {
                    DevicePortalException innerException = e.InnerException as DevicePortalException;

                    Console.WriteLine(string.Format("Exception encountered: {0}, hr = 0x{1:X} : {2}", innerException.StatusCode, innerException.HResult, innerException.Reason));
                }
                else
                {
                    Console.WriteLine(string.Format("Unexpected exception encountered: {0}", e.Message));
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
+3 −3
Original line number Diff line number Diff line
@@ -152,11 +152,11 @@ namespace Microsoft.Tools.WindowsDevicePortal
        /// <summary>
        /// Checks a response to see if it failed due to a bad CSRF token.
        /// </summary>
        /// <param name="response">The response from the REST call.</param>
        /// <param name="exception">The DevicePortalException from the REST call.</param>
        /// <returns>Whether the response failed due to the bad CSRF token.</returns>
        private bool IsBadCsrfToken(HttpResponseMessage response)
        private bool IsBadCsrfToken(DevicePortalException exception)
        {
            return response.StatusCode == HttpStatusCode.Forbidden && response.ReasonPhrase.Equals("CSRF Token Invalid");
            return exception.StatusCode == HttpStatusCode.Forbidden && exception.Reason.Equals("CSRF Token Invalid");
        }

        /// <summary>
+27 −7
Original line number Diff line number Diff line
@@ -37,10 +37,12 @@ namespace Microsoft.Tools.WindowsDevicePortal
        /// <typeparam name="T">The type of the data for the HTTP response body (if present).</typeparam>
        /// <param name="apiPath">The relative portion of the uri path that specifies the API to call.</param>
        /// <param name="payload">The query string portion of the uri path that provides the parameterized data.</param>
        /// <param name="allowRetry">Allow the Delete to be retried after refreshing the CSRF token.</param>
        /// <returns>Task tracking the HTTP completion.</returns>
        private async Task<T> Delete<T>(
            string apiPath,
            string payload = null) where T : new()
            string payload = null,
            bool allowRetry = true) where T : new()
        {
            T data = default(T);

@@ -51,6 +53,8 @@ namespace Microsoft.Tools.WindowsDevicePortal

            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

            try
            {
                using (Stream dataStream = await this.Delete(uri))
                {
                    if ((dataStream != null) &&
@@ -62,6 +66,22 @@ namespace Microsoft.Tools.WindowsDevicePortal
                        data = (T)response;
                    }
                }
            }
            catch (DevicePortalException e)
            {
                // If this isn't a retry and it failed due to a bad CSRF
                // token, refresh the token and then retry.
                if (allowRetry && this.IsBadCsrfToken(e))
                {
                    await this.RefreshCsrfToken();
                    return await this.Delete<T>(apiPath, payload, false);
                }
                else
                {
                    throw e;
                }
            }


            return data;
        }
+28 −7
Original line number Diff line number Diff line
@@ -80,12 +80,14 @@ namespace Microsoft.Tools.WindowsDevicePortal
        /// <param name="payload">The query string portion of the uri path that provides the parameterized data.</param>
        /// <param name="requestStream">Optional stream containing data for the request body.</param>
        /// <param name="requestStreamContentType">The type of that request body data.</param>
        /// <param name="allowRetry">Allow the Post to be retried after issuing a Get call. Currently used for CSRF failures.</param>
        /// <returns>Task tracking the POST completion.</returns>
        private async Task<T> Post<T>(
            string apiPath,
            string payload = null,
            Stream requestStream = null,
            string requestStreamContentType = null) where T : new()
            string requestStreamContentType = null,
            bool allowRetry = true) where T : new()
        {
            T data = default(T);

@@ -96,6 +98,8 @@ namespace Microsoft.Tools.WindowsDevicePortal

            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

            try
            {
                using (Stream dataStream = await this.Post(uri, requestStream, requestStreamContentType))
                {
                    if ((dataStream != null) &&
@@ -107,6 +111,23 @@ namespace Microsoft.Tools.WindowsDevicePortal
                        data = (T)response;
                    }
                }
            }
            catch (DevicePortalException e)
            {
                // If this isn't a retry and it failed due to a bad CSRF
                // token, refresh the token and then retry. 
                // Note: due to the stream already being disposed, we can't
                // retry a POST unless a body stream isn't being provided.
                if (allowRetry && this.IsBadCsrfToken(e) && requestStream == null)
                {
                    await this.RefreshCsrfToken();
                    return await this.Post<T>(apiPath, payload, null, null, false);
                }
                else
                {
                    throw e;
                }
            }

            return data;
        }
+26 −7
Original line number Diff line number Diff line
@@ -57,11 +57,13 @@ namespace Microsoft.Tools.WindowsDevicePortal
        /// <param name="apiPath">The relative portion of the uri path that specifies the API to call.</param>
        /// <param name="bodyData">The data to be used for the HTTP request body.</param>
        /// <param name="payload">The query string portion of the uri path that provides the parameterized data.</param>
        /// <param name="allowRetry">Allow the Put to be retried after refreshing the CSRF token.</param>
        /// <returns>Task tracking the PUT completion, optional response body.</returns>
        private async Task<T> Put<T, K>(
            string apiPath,
            K bodyData = null,
            string payload = null) where T : new()
            string payload = null,
            bool allowRetry = true) where T : new()
                                   where K : class
        {
            T data = default(T);
@@ -96,6 +98,8 @@ namespace Microsoft.Tools.WindowsDevicePortal

            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

            try
            {
                using (Stream dataStream = await this.Put(uri, streamContent))
                {
                    if ((dataStream != null) &&
@@ -107,6 +111,21 @@ namespace Microsoft.Tools.WindowsDevicePortal
                        data = (T)response;
                    }
                }
            }
            catch (DevicePortalException e)
            {
                // If this isn't a retry and it failed due to a bad CSRF
                // token, refresh the token and then retry.
                if (allowRetry && this.IsBadCsrfToken(e))
                {
                    await this.RefreshCsrfToken();
                    return await this.Put<T, K>(apiPath, bodyData, payload, false);
                }
                else
                {
                    throw e;
                }
            }

            return data;
        }
Loading