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); 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().ConfigureAwait(false)) { 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().ConfigureAwait(false); { 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).ConfigureAwait(false)) != 0) { ms.Write(bufferRead, 0, read); 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)stream.ReadToEnd())); } 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; 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()); GetAccessTokenResponse tokenResponse; try { tokenResponse = uri.PostJsonToUrl(refreshRequest) .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; if (string.IsNullOrEmpty(accessToken)) { throw new RefreshTokenException("Could not retrieve new AccessToken from: " + uri); } var refreshClient = webReq = (HttpWebRequest)WebRequest.Create(requestUri); if (this.CookieContainer.GetTokenCookie(BaseUri) != 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).ConfigureAwait(false)); } 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).ConfigureAwait(false)); } 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(); } } }
private void HandleResponseError <TResponse>(Exception exception, AsyncState <TResponse> state) { var webEx = exception as WebException; if (PclExportClient.Instance.IsWebException(webEx)) { var errorResponse = (HttpWebResponse)webEx.Response; Log.Error(webEx); if (Log.IsDebugEnabled) { Log.Debug($"Status Code : {errorResponse.StatusCode}"); Log.Debug($"Status Description : {errorResponse.StatusDescription}"); } var serviceEx = new WebServiceException(errorResponse.StatusDescription) { StatusCode = (int)errorResponse.StatusCode, StatusDescription = errorResponse.StatusDescription, ResponseHeaders = errorResponse.Headers }; try { using (var stream = errorResponse.GetResponseStream()) { var bytes = stream.ReadFully(); serviceEx.ResponseBody = bytes.FromUtf8Bytes(); var errorResponseType = WebRequestUtils.GetErrorResponseDtoType <TResponse>(state.Request); if (stream.CanSeek) { PclExport.Instance.ResetStream(stream); serviceEx.ResponseDto = this.StreamDeserializer(errorResponseType, stream); } else //Android { using (var ms = MemoryStreamFactory.GetStream(bytes)) { serviceEx.ResponseDto = this.StreamDeserializer(errorResponseType, ms); } } state.HandleError(serviceEx.ResponseDto, serviceEx); } } catch (Exception innerEx) { // Oh, well, we tried Log.Debug($"WebException Reading Response Error: {innerEx.Message}", innerEx); state.HandleError(default(TResponse), new WebServiceException(errorResponse.StatusDescription, innerEx) { StatusCode = (int)errorResponse.StatusCode, StatusDescription = errorResponse.StatusDescription, ResponseHeaders = errorResponse.Headers }); } return; } var authEx = exception as AuthenticationException; if (authEx != null) { var customEx = WebRequestUtils.CreateCustomException(state.Url, authEx); Log.Debug($"AuthenticationException: {customEx.Message}", customEx); state.HandleError(default(TResponse), authEx); } Log.Debug($"Exception Reading Response Error: {exception.Message}", exception); state.HandleError(default(TResponse), exception); CancelAsyncFn = null; }
private void HandleResponseError <TResponse>(Exception exception, AsyncState <TResponse> state) { var webEx = exception as WebException; if (webEx.IsWebException()) { var errorResponse = ((HttpWebResponse)webEx.Response); Log.Error(webEx); Log.DebugFormat("Status Code : {0}", errorResponse.StatusCode); Log.DebugFormat("Status Description : {0}", errorResponse.StatusDescription); var serviceEx = new WebServiceException(errorResponse.StatusDescription) { StatusCode = (int)errorResponse.StatusCode, StatusDescription = errorResponse.StatusDescription, }; try { using (var stream = errorResponse.GetResponseStream()) { //Uncomment to Debug exceptions: //var strResponse = new StreamReader(stream).ReadToEnd(); //Console.WriteLine("Response: " + strResponse); //stream.Position = 0; serviceEx.ResponseBody = stream.ReadFully().FromUtf8Bytes(); PclExport.Instance.ResetStream(stream); serviceEx.ResponseDto = this.StreamDeserializer(typeof(TResponse), stream); state.HandleError((TResponse)serviceEx.ResponseDto, serviceEx); } } catch (Exception innerEx) { // Oh, well, we tried Log.Debug(string.Format("WebException Reading Response Error: {0}", innerEx.Message), innerEx); state.HandleError(default(TResponse), new WebServiceException(errorResponse.StatusDescription, innerEx) { StatusCode = (int)errorResponse.StatusCode, StatusDescription = errorResponse.StatusDescription, }); } return; } var authEx = exception as AuthenticationException; if (authEx != null) { var customEx = WebRequestUtils.CreateCustomException(state.Url, authEx); Log.Debug(string.Format("AuthenticationException: {0}", customEx.Message), customEx); state.HandleError(default(TResponse), authEx); } Log.Debug(string.Format("Exception Reading Response Error: {0}", exception.Message), exception); state.HandleError(default(TResponse), exception); CancelAsyncFn = null; }
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()); GetAccessTokenResponse tokenResponse; try { tokenResponse = uri.PostJsonToUrl(refreshRequest).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; if (string.IsNullOrEmpty(accessToken)) { throw new RefreshTokenException("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 (WebServiceException rethrow) { requestState.HandleError(default(T), rethrow); } 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); } }
private void ResponseCallback <T>(IAsyncResult asyncResult) { var requestState = (AsyncState <T>)asyncResult.AsyncState; try { var webRequest = requestState.WebRequest; requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult); 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 firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1; if (firstCall && WebRequestUtils.ShouldAuthenticate(ex, this.UserName, this.Password)) { try { requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url); if (StoreCookies) { requestState.WebRequest.CookieContainer = CookieContainer; } requestState.WebRequest.AddBasicAuth(this.UserName, this.Password); if (OnAuthenticationRequired != null) { OnAuthenticationRequired(requestState.WebRequest); } SendWebRequestAsync( requestState.HttpMethod, requestState.Request, requestState, requestState.WebRequest); } catch (Exception /*subEx*/) { HandleResponseError(ex, requestState); } return; } HandleResponseError(ex, requestState); } }