/// <summary> /// Reads the file from the server url. /// In case of errors reading the file from the server, returned <see cref="T:Coding4Fun.VisualStudio.RemoteControl.GetFileResult" /> object's /// IsSuccessStatusCode value will be false. /// </summary> /// <returns>Information about the file obtained from the server</returns> async Task <GetFileResult> IRemoteControlHTTPRequestor.GetFileFromServerAsync() { GetFileResult result = new GetFileResult { Code = HttpStatusCode.Unused }; try { int i = 0; while (true) { if (i >= 2) { return(result); } if (i > 0) { int num = Math.Min(32, (int)Math.Pow(2.0, i)); try { await Task.Delay(num * 1000, cancellationTokenSource.Token).ConfigureAwait(false); } catch (OperationCanceledException) { return(result); } catch (ObjectDisposedException) { return(result); } result.Dispose(); } result = await GetFile(url, httpRequestTimeoutMillis, ServerRevalidatePolicy).ConfigureAwait(false); if (result.IsSuccessStatusCode) { break; } i++; } return(result); } finally { if (!result.IsSuccessStatusCode && Platform.IsWindows) { WinINetHelper.WriteErrorResponseToCache(errorMarkerFileUrl, result.Code); } } }
/// <summary> /// This is the HTTP-facing method in the class. It essentially performs all functions of /// 1. sending an HTTP request for the file /// 2. if the response is from the server, ensuring that it is added to the IE cache /// 3. additonal logic to cache error responses in the IE cache. By default error /// responses are not cached. /// </summary> /// <param name="requestUrl"></param> /// <param name="requestTimeoutMillis"></param> /// <param name="cachePolicy">Specifies chache policy to use when sending the request</param> /// <returns>Result of the file lookup. See <see cref="T:Coding4Fun.VisualStudio.RemoteControl.GetFileResult" /> for details.</returns> private async Task <GetFileResult> GetFile(string requestUrl, int requestTimeoutMillis, HttpRequestCachePolicy cachePolicy) { HttpWebRequest request = CreateHttpRequest(requestUrl); if (request == null) { return(new GetFileResult { ErrorMessage = "Create HTTP Request Error", Code = HttpStatusCode.Unused }); } request.Timeout = requestTimeoutMillis; request.CachePolicy = (cachePolicy ?? new HttpRequestCachePolicy(HttpCacheAgeControl.MaxStale, TimeSpan.MaxValue)); request.AutomaticDecompression = (DecompressionMethods.GZip | DecompressionMethods.Deflate); HttpWebResponse resp = null; WebException exception = null; try { Task <WebResponse> requestTask = request.GetResponseAsync(); bool shouldAbort = false; try { if (await Task.WhenAny(requestTask, Task.Delay(requestTimeoutMillis, cancellationTokenSource.Token)).ConfigureAwait(false) != requestTask) { shouldAbort = true; } } catch (Exception) { shouldAbort = true; } if (shouldAbort) { request.Abort(); requestTask.SwallowException(); return(new GetFileResult { ErrorMessage = "Request timed out", Code = HttpStatusCode.Unused }); } _ = resp; resp = (HttpWebResponse)(await requestTask.ConfigureAwait(false)); } catch (WebException ex2) { exception = ex2; } catch (Exception ex3) { return(new GetFileResult { ErrorMessage = "Unknown Exception: " + ex3.Message, Code = HttpStatusCode.Unused }); } string errorMessage2 = null; if (exception != null) { WebExceptionStatus status = exception.Status; if (status != WebExceptionStatus.ProtocolError) { errorMessage2 = string.Format(CultureInfo.InvariantCulture, "Non-Protocol Error {0}", new object[1] { Enum.GetName(typeof(WebExceptionStatus), exception.Status) }); return(new GetFileResult { ErrorMessage = errorMessage2, Code = HttpStatusCode.Unused }); } resp = (exception.Response as HttpWebResponse); errorMessage2 = string.Format(CultureInfo.InvariantCulture, "Protocol Error {0}", new object[1] { Enum.GetName(typeof(HttpStatusCode), resp.StatusCode) }); } if (resp != null) { int? ageInSeconds = ExtractAgeHeaderValue(resp); Stream stream = null; bool shouldDisposeResponseStream = false; try { if (!resp.IsFromCache) { shouldDisposeResponseStream = true; switch (resp.StatusCode) { case HttpStatusCode.OK: stream = await Task.Run(() => CopyToFileStream(resp.GetResponseStream())).ConfigureAwait(false); break; case HttpStatusCode.NotFound: if (Platform.IsWindows) { WinINetHelper.WriteErrorResponseToCache(requestUrl, HttpStatusCode.NotFound); } break; } } return(new GetFileResult { Code = resp.StatusCode, RespStream = ((resp.StatusCode == HttpStatusCode.OK) ? (stream ?? resp.GetResponseStream()) : null), AgeSeconds = ageInSeconds, IsFromCache = resp.IsFromCache, ErrorMessage = errorMessage2 }); } catch (UnauthorizedAccessException ex4) { shouldDisposeResponseStream = true; errorMessage2 = ex4.Message; } catch (OperationCanceledException) { shouldDisposeResponseStream = true; errorMessage2 = "Download was cancelled by caller"; } catch (ObjectDisposedException) { shouldDisposeResponseStream = true; errorMessage2 = "Download was cancelled by caller"; } catch (WebException) { shouldDisposeResponseStream = true; errorMessage2 = "Reading HTTP response stream throws an WebException"; } finally { if (shouldDisposeResponseStream || resp.StatusCode != HttpStatusCode.OK) { resp.GetResponseStream()?.Dispose(); } } return(new GetFileResult { ErrorMessage = errorMessage2, Code = HttpStatusCode.Unused }); } throw new InvalidOperationException("WebException is protocol, but response is null", exception); }