Beispiel #1
0
        private async Task <T> SendWebRequestAsync <T>(string httpMethod, string absoluteUrl, object request, CancellationToken token, bool recall = false)
        {
            if (httpMethod == null)
            {
                throw new ArgumentNullException(nameof(httpMethod));
            }

            this.PopulateRequestMetadata(request);

            var requestUri     = absoluteUrl;
            var hasQueryString = request != null && !HttpUtils.HasRequestBody(httpMethod);

            if (hasQueryString)
            {
                var queryString = QueryStringSerializer.SerializeToString(request);
                if (!string.IsNullOrEmpty(queryString))
                {
                    requestUri += "?" + queryString;
                }
            }

            var webReq = this.CreateHttpWebRequest(requestUri);

            if (webReq != null && Proxy != null)
            {
                webReq.Proxy = Proxy;
            }

            var    timedOut = false;
            ITimer timer    = null;

            timer = PclExportClient.Instance.CreateTimer(state =>
            {
                timedOut = true;
                webReq?.Abort();
                webReq = null;
                timer?.Cancel();
                timer = null;
            }, this.Timeout.GetValueOrDefault(DefaultTimeout), this);

            Exception ResolveException(Exception ex)
            {
                if (token.IsCancellationRequested)
                {
                    return(new OperationCanceledException(token));
                }
                if (timedOut)
                {
                    return(PclExportClient.Instance.CreateTimeoutException(ex, "The request timed out"));
                }
                return(ex);
            }

            bool            returningWebResponse = false;
            HttpWebResponse webRes = null;

            T Complete(T response)
            {
                timer.Cancel();
                PclExportClient.Instance.SynchronizeCookies(this);
                ResultsFilterResponse?.Invoke(webRes, response, httpMethod, absoluteUrl, request);
                return(response);
            }

            webReq.Accept = ContentType;

            if (this.EmulateHttpViaPost)
            {
                webReq.Method = "POST";
                webReq.Headers[HttpHeaders.XHttpMethodOverride] = httpMethod;
            }
            else
            {
                webReq.Method = httpMethod;
            }

            PclExportClient.Instance.AddHeader(webReq, Headers);
            PclExport.Instance.Config(webReq, userAgent: UserAgent);

            if (this.authInfo != null && !string.IsNullOrEmpty(this.UserName))
            {
                webReq.AddAuthInfo(this.UserName, this.Password, authInfo);
            }
            else if (this.BearerToken != null)
            {
                webReq.Headers[HttpHeaders.Authorization] = "Bearer " + this.BearerToken;
            }
            else if (this.Credentials != null)
            {
                webReq.Credentials = this.Credentials;
            }
            else if (this.AlwaysSendBasicAuthHeader)
            {
                webReq.AddBasicAuth(this.UserName, this.Password);
            }

            if (!DisableAutoCompression)
            {
                PclExport.Instance.AddCompression(webReq);
            }

            ApplyWebRequestFilters(webReq);

            try
            {
                if (HttpUtils.HasRequestBody(webReq.Method))
                {
                    webReq.ContentType = ContentType;

                    if (RequestCompressionType != null)
                    {
                        webReq.Headers[HttpHeaders.ContentEncoding] = RequestCompressionType;
                    }

                    using var requestStream = await webReq.GetRequestStreamAsync().ConfigAwait();

                    token.ThrowIfCancellationRequested();
                    if (request != null)
                    {
                        StreamSerializer(null, request, requestStream);
                    }
                }
            }
            catch (Exception ex)
            {
                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Error Sending Request: {ex.Message}", ex);
                }

                throw HandleResponseError <T>(ResolveException(ex), requestUri, request);
            }

            try
            {
                webRes = (HttpWebResponse)await webReq.GetResponseAsync().ConfigAwait();

                {
                    token.ThrowIfCancellationRequested();

                    ApplyWebResponseFilters(webRes);

                    returningWebResponse = typeof(T) == typeof(HttpWebResponse);
                    if (returningWebResponse)
                    {
                        return(Complete((T)(object)webRes));
                    }

                    var responseStream = webRes.ResponseStream();

                    var responseBodyLength = webRes.ContentLength;
                    var bufferRead         = new byte[BufferSize];

                    var totalRead = 0;
                    int read;
                    var ms = MemoryStreamFactory.GetStream();

                    while ((read = await responseStream.ReadAsync(bufferRead, 0, bufferRead.Length, token).ConfigAwait()) != 0)
                    {
                        await ms.WriteAsync(bufferRead, 0, read, token).ConfigAwait();

                        totalRead += read;
                        OnDownloadProgress?.Invoke(totalRead, responseBodyLength);
                    }

                    try
                    {
                        ms.Position = 0;
                        if (typeof(T) == typeof(Stream))
                        {
                            return(Complete((T)(object)ms));
                        }
                        else
                        {
                            var stream = ms;
                            try
                            {
                                if (typeof(T) == typeof(string))
                                {
                                    return(Complete((T)(object)await stream.ReadToEndAsync().ConfigAwait()));
                                }
                                else if (typeof(T) == typeof(byte[]))
                                {
                                    return(Complete((T)(object)stream.ToArray()));
                                }
                                else
                                {
                                    return(Complete((T)this.StreamDeserializer(typeof(T), stream)));
                                }
                            }
                            finally
                            {
                                if (stream.CanRead)
                                {
                                    stream.Dispose(); // Not yet disposed, but could've been.
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug($"Error Reading Response Error: {ex.Message}", ex);
                        }

                        throw;
                    }
                    finally
                    {
                        responseStream.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                var webEx                 = ex as WebException;
                var firstCall             = !recall;
                var hasRefreshTokenCookie = this.CookieContainer.GetRefreshTokenCookie(BaseUri) != null;
                var hasRefreshToken       = RefreshToken != null || hasRefreshTokenCookie;

                if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx,
                                                                    (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) ||
                                                                    Credentials != null ||
                                                                    BearerToken != null ||
                                                                    hasRefreshToken ||
                                                                    OnAuthenticationRequired != null))
                {
                    try
                    {
                        if (hasRefreshToken)
                        {
                            var refreshRequest = new GetAccessToken {
                                RefreshToken   = RefreshToken,
                                UseTokenCookie = UseTokenCookie,
                            };
                            var uri = this.RefreshTokenUri ?? this.BaseUri.CombineWith(refreshRequest.ToPostUrl());

                            GetAccessTokenResponse tokenResponse;
                            try
                            {
                                tokenResponse = (await uri.PostJsonToUrlAsync(refreshRequest, requestFilter: req => {
                                    if (UseTokenCookie || hasRefreshTokenCookie)
                                    {
                                        req.CookieContainer = CookieContainer;
                                    }
                                }, token: token).ConfigAwait()).FromJson <GetAccessTokenResponse>();
                            }
                            catch (WebException refreshEx)
                            {
                                var webServiceEx = ServiceClientBase.ToWebServiceException(refreshEx,
                                                                                           stream => StreamDeserializer(typeof(T), stream),
                                                                                           ContentType);

                                if (webServiceEx != null)
                                {
                                    throw new RefreshTokenException(webServiceEx);
                                }

                                throw new RefreshTokenException(refreshEx.Message, refreshEx);
                            }

                            var accessToken   = tokenResponse?.AccessToken;
                            var refreshClient = webReq = (HttpWebRequest)WebRequest.Create(requestUri);
                            var tokenCookie   = this.CookieContainer.GetTokenCookie(BaseUri);

                            if (UseTokenCookie)
                            {
                                if (tokenCookie == null)
                                {
                                    throw new RefreshTokenException("Could not retrieve new AccessToken Cooke from: " + uri);
                                }

                                refreshClient.CookieContainer.SetTokenCookie(BaseUri, tokenCookie);
                            }
                            else
                            {
                                if (string.IsNullOrEmpty(accessToken))
                                {
                                    throw new RefreshTokenException("Could not retrieve new AccessToken from: " + uri);
                                }

                                if (tokenCookie != null)
                                {
                                    this.CookieContainer.SetTokenCookie(accessToken, BaseUri);
                                    refreshClient.CookieContainer.SetTokenCookie(BaseUri, accessToken);
                                }
                                else
                                {
                                    refreshClient.AddBearerToken(this.BearerToken = accessToken);
                                }
                            }

                            return(await SendWebRequestAsync <T>(httpMethod, absoluteUrl, request, token, recall : true).ConfigAwait());
                        }

                        OnAuthenticationRequired?.Invoke();

                        var newReq = (HttpWebRequest)WebRequest.Create(requestUri);

                        if (StoreCookies)
                        {
                            newReq.CookieContainer = CookieContainer;
                        }

                        HandleAuthException(ex, webReq);

                        return(await SendWebRequestAsync <T>(httpMethod, absoluteUrl, request, token, recall : true).ConfigAwait());
                    }
                    catch (WebServiceException)
                    {
                        throw;
                    }
                    catch (Exception /*subEx*/)
                    {
                        throw HandleResponseError <T>(ResolveException(ex), requestUri, request);
                    }
                }

                if (ExceptionFilter != null && webEx?.Response != null)
                {
                    var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestUri, typeof(T));
                    if (cachedResponse is T variable)
                    {
                        return(variable);
                    }
                }

                throw HandleResponseError <T>(ResolveException(ex), requestUri, request);
            }
            finally
            {
                if (!returningWebResponse)
                {
                    webRes?.Dispose();
                }
            }
        }
Beispiel #2
0
        private void ResponseCallback <T>(IAsyncResult asyncResult)
        {
            var requestState = (AsyncState <T>)asyncResult.AsyncState;

            try
            {
                requestState.Token.ThrowIfCancellationRequested();

                var webRequest = requestState.WebRequest;

                requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult);

                requestState.OnResponseInit?.Invoke(requestState.WebResponse);

                if (requestState.ResponseContentLength == default(long))
                {
                    requestState.ResponseContentLength = requestState.WebResponse.ContentLength;
                }

                ApplyWebResponseFilters(requestState.WebResponse);

                if (typeof(T) == typeof(HttpWebResponse))
                {
                    requestState.HandleSuccess((T)(object)requestState.WebResponse);
                    return;
                }

                // Read the response into a Stream object.
#if NETSTANDARD1_1 || NETSTANDARD1_6
                var responseStream = requestState.WebResponse.GetResponseStream()
                                     .Decompress(requestState.WebResponse.Headers[HttpHeaders.ContentEncoding]);
#else
                var responseStream = requestState.WebResponse.GetResponseStream();
#endif
                requestState.ResponseStream = responseStream;

                var task = responseStream.ReadAsync(requestState.BufferRead, 0, BufferSize);
                ReadCallBack(task, requestState);
            }
            catch (Exception ex)
            {
                var webEx     = ex as WebException;
                var firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1;
                if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx,
                                                                    (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) ||
                                                                    Credentials != null ||
                                                                    BearerToken != null ||
                                                                    RefreshToken != null ||
                                                                    OnAuthenticationRequired != null))
                {
                    try
                    {
                        if (RefreshToken != null)
                        {
                            var refreshRequest = new GetAccessToken {
                                RefreshToken = RefreshToken
                            };
                            var uri           = this.RefreshTokenUri ?? this.BaseUri.CombineWith(refreshRequest.ToPostUrl());
                            var tokenResponse = uri.PostJsonToUrl(refreshRequest).FromJson <GetAccessTokenResponse>();
                            var accessToken   = tokenResponse?.AccessToken;
                            if (string.IsNullOrEmpty(accessToken))
                            {
                                throw new Exception("Could not retrieve new AccessToken from: " + uri);
                            }

                            var refreshClient = requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url);
                            if (this.CookieContainer.GetTokenCookie(BaseUri) != null)
                            {
                                this.CookieContainer.SetTokenCookie(accessToken, BaseUri);
                                refreshClient.CookieContainer.SetTokenCookie(BaseUri, accessToken);
                            }
                            else
                            {
                                refreshClient.AddBearerToken(this.BearerToken = accessToken);
                            }

                            SendWebRequestAsync(
                                requestState.HttpMethod, requestState.Request,
                                requestState, requestState.WebRequest);

                            return;
                        }

                        OnAuthenticationRequired?.Invoke();

                        requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url);

                        if (StoreCookies)
                        {
                            requestState.WebRequest.CookieContainer = CookieContainer;
                        }

                        HandleAuthException(ex, requestState.WebRequest);

                        SendWebRequestAsync(
                            requestState.HttpMethod, requestState.Request,
                            requestState, requestState.WebRequest);
                    }
                    catch (Exception /*subEx*/)
                    {
                        HandleResponseError(ex, requestState);
                    }
                    return;
                }

                if (ExceptionFilter != null && webEx != null && webEx.Response != null)
                {
                    var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestState.Url, typeof(T));
                    if (cachedResponse is T)
                    {
                        requestState.OnSuccess((T)cachedResponse);
                        return;
                    }
                }

                HandleResponseError(ex, requestState);
            }
        }
Beispiel #3
0
        private void ResponseCallback <T>(IAsyncResult asyncResult)
        {
            var requestState = (AsyncState <T>)asyncResult.AsyncState;

            try
            {
                requestState.Token.ThrowIfCancellationRequested();

                var webRequest = requestState.WebRequest;

                requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult);

                requestState.OnResponseInit?.Invoke(requestState.WebResponse);

                if (requestState.ResponseContentLength == default(long))
                {
                    requestState.ResponseContentLength = requestState.WebResponse.ContentLength;
                }

                ApplyWebResponseFilters(requestState.WebResponse);

                if (typeof(T) == typeof(HttpWebResponse))
                {
                    requestState.HandleSuccess((T)(object)requestState.WebResponse);
                    return;
                }

                // Read the response into a Stream object.
                var responseStream = requestState.WebResponse.GetResponseStream();
                requestState.ResponseStream = responseStream;

                var task = responseStream.ReadAsync(requestState.BufferRead, 0, BufferSize);
                ReadCallBack(task, requestState);
            }
            catch (Exception ex)
            {
                var webEx     = ex as WebException;
                var firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1;
                if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx,
                                                                    (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) ||
                                                                    Credentials != null ||
                                                                    BearerToken != null ||
                                                                    OnAuthenticationRequired != null))
                {
                    try
                    {
                        OnAuthenticationRequired?.Invoke();

                        requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url);

                        if (StoreCookies)
                        {
                            requestState.WebRequest.CookieContainer = CookieContainer;
                        }

                        HandleAuthException(ex, requestState.WebRequest);

                        SendWebRequestAsync(
                            requestState.HttpMethod, requestState.Request,
                            requestState, requestState.WebRequest);
                    }
                    catch (Exception /*subEx*/)
                    {
                        HandleResponseError(ex, requestState);
                    }
                    return;
                }

                if (ExceptionFilter != null && webEx != null && webEx.Response != null)
                {
                    var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestState.Url, typeof(T));
                    if (cachedResponse is T)
                    {
                        requestState.OnSuccess((T)cachedResponse);
                        return;
                    }
                }

                HandleResponseError(ex, requestState);
            }
        }