/// <summary> /// This is the method that is called to configure the <see cref="NetStd20HttpRequest.RequestClient"/> /// and <see cref="NetStd20HttpRequest.RequestHandler"/> returned by <see cref="CreateWebRequest(string, Uri)"/>. /// </summary> /// <param name="request">Value returned by <see cref="CreateWebRequest(string, Uri)"/>.</param> protected override NetStd20HttpRequest ConfigureWebRequest(NetStd20HttpRequest request) { // Must ensure this method is thread-safe because the parent method will update // NetStd20HttpRequest.RequestHandler properties, which is really just calling NamedHttpClientHandlerWrapper. // We don't want multiple threads to be updating NamedHttpClientHandlerWrapper properties at the same // time because the wrapped HttpClientHandler properties are probably not thread-safe, and we don't want // another thread to add to the wrapper while we are updating wrapper's current set of handlers. NamedHttpClientHandlerWrapper wrapper = request.RequestHandler; // The lock will prevent new handlers from being added in the HttpEngineFactory.AddNamedClientHandler() method above. lock (wrapper) { // By this point, it is an error if we do not have access to the HttpClientHandler associated with the named client. // Because we clear the wrapper at the end of this code block, wrapper may be empty if we had previously // configured the named HttpClientHandler already. The IsAlwaysEmpty property gets around this issue. if (wrapper.IsAlwaysEmpty) { throw new InvalidOperationException(string.Format( "HttpClientHandler for the named client '{0}' has not been registered with MiniRestSharp. Did you forget to call RestSharpServiceCollectionExtensions.AddRestSharpClient(IServiceCollection, string)?", wrapper.Name)); } // I've confirmed that the only place the wrapped HttpClientHandlers are configured is in this method. NetStd20HttpRequest returnValue = base.ConfigureWebRequest(request); // Now that the wrapped HttpClientHandlers are configured, we remove them from the wrapper // since we can't configure them again anyway. It's of course possible that these handlers // get recycled by IHttpClientFactory and become configurable again. When this happens I think the // RestSharpServiceCollectionExtensions system will end up calling HttpEngineFactory.AddNamedClientHandler() // again, which will result in it being added to wrapper again for another round of configuration later. wrapper.Clear(); return(returnValue); } }
private async Task <HttpResponse> PostPutInternal(string method) { NetStd20HttpRequest request = this.CreateWebRequest(method, this.Url); this.ConfigureWebRequest(request); this.PreparePostBody(request.RequestMessage); this.WriteRequestBody(request); return(await this.GetResponse(request)); }
private async Task <HttpResponse> GetStyleMethodInternal(string method) { NetStd20HttpRequest request = this.CreateWebRequest(method, this.Url); this.ConfigureWebRequest(request); if (this.HasBody && (method == "DELETE" || method == "OPTIONS")) { request.RequestMessage.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(this.RequestContentType); this.WriteRequestBody(request); } return(await this.GetResponse(request)); }
protected virtual NetStd20HttpRequest ConfigureWebRequest(NetStd20HttpRequest request) { ////////// 1. Configure HttpRequestMessage. this.AppendHeaders(request.RequestMessage); // Override certain headers that are controlled by RestSharp. request.RequestMessage.Headers.TE.Clear(); request.RequestMessage.Headers.TE.Add(new TransferCodingWithQualityHeaderValue("deflate")); request.RequestMessage.Headers.TE.Add(new TransferCodingWithQualityHeaderValue("gzip")); request.RequestMessage.Headers.TE.Add(new TransferCodingWithQualityHeaderValue("identity")); if (this.UserAgent.HasValue()) { request.RequestMessage.Headers.UserAgent.Add(ProductInfoHeaderValue.Parse(this.UserAgent)); } ////////// 2. Configure HttpClientHandler this.AppendCookies(request.RequestHandler, request.RequestMessage.RequestUri); // This matches with request.Headers.TE header. request.RequestHandler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip | DecompressionMethods.None; // Handler credentials. request.RequestHandler.UseDefaultCredentials = this.UseDefaultCredentials; if (this.Credentials != null) { request.RequestHandler.Credentials = this.Credentials; } // redirects request.RequestHandler.AllowAutoRedirect = this.FollowRedirects; if (this.FollowRedirects && this.MaxRedirects.HasValue) { request.RequestHandler.MaxAutomaticRedirections = this.MaxRedirects.Value; } ////////// 3. Configure HttpClient if (this.Timeout != 0) { request.RequestClient.Timeout = TimeSpan.FromMilliseconds(this.Timeout); } return(request); }
private async Task <HttpResponse> GetResponse(NetStd20HttpRequest request) { HttpResponse response = new HttpResponse { ResponseStatus = ResponseStatus.None }; try { NetStd20HttpResponse webResponse = await GetRawResponse(request); this.ExtractResponseData(response, webResponse); } catch (Exception ex) { this.ExtractErrorResponse(response, ex); } return(response); }
private void WriteRequestBody(NetStd20HttpRequest webRequest) { if (this.HasBody || this.HasFiles || this.AlwaysMultipartFormData) { webRequest.RequestMessage.Content.Headers.ContentLength = this.CalculateContentLength(); } using (Stream requestStream = webRequest.GetRequestStreamAsync()) { if (this.HasFiles || this.AlwaysMultipartFormData) { this.WriteMultipartFormData(requestStream); } else if (this.RequestBodyBytes != null) { requestStream.Write(this.RequestBodyBytes, 0, this.RequestBodyBytes.Length); } else if (this.RequestBody != null) { this.WriteStringTo(requestStream, this.RequestBody); } } }
private static async Task <NetStd20HttpResponse> GetRawResponse(NetStd20HttpRequest request) { try { // Some methods do not allow entity-body in request, so we must remove the HttpContent. // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for which method allows/disallows entity-body. // We need to do this because in the constructor of NetStd20HttpRequest, we always set a HttpContent to make // programming easier. In netstandard2.0, the framework does not allow HttpContent for methods such as GET. HttpMethod requestMethod = request.RequestMessage.Method; if (requestMethod == HttpMethod.Delete || requestMethod == HttpMethod.Get || requestMethod == HttpMethod.Head || requestMethod == HttpMethod.Options) { // Will also remove any HttpContent-specific headers that may have been set erroneously. request.RequestMessage.Content = null; } return(await request.GetResponseAsync()); } catch (WebException ex) { // Check to see if this is an HTTP error or a transport error. // In cases where an HTTP error occurs ( status code >= 400 ) // return the underlying HTTP response, otherwise assume a // transport exception (ex: connection timeout) and // rethrow the exception var exResponse = ex.Response as NetStd20HttpResponse; if (exResponse != null) { return(exResponse); } throw; } }