private bool DefaultMatchingAlgorithm( InterceptedRequest interceptedRequest, RecordedRequest recordedRequest) { if (null == interceptedRequest || null == recordedRequest) { return(false); } var urlMatches = string.Equals( interceptedRequest.HttpWebRequest.RequestUri?.ToString().RemoveTrailingSlash() ?? "", recordedRequest.Url?.RemoveTrailingSlash(), StringComparison.InvariantCultureIgnoreCase); var methodMatches = string.Equals( interceptedRequest.HttpWebRequest.Method ?? "", recordedRequest.Method, StringComparison.InvariantCultureIgnoreCase); var requestPayloadMatches = true == interceptedRequest?.RequestPayload.Equals(recordedRequest.RequestPayload); var requestHeadersMatch = recordedRequest.RequestHeaders.Equals(interceptedRequest.HttpWebRequest.Headers); return (urlMatches && methodMatches && requestPayloadMatches && requestHeadersMatch); }
/// <summary> /// 1. Use <see cref="MatchingAlgorithm"/> to find a match from <see cref="RecordedRequests"/>. /// <para /> /// 2. Use either <see cref="RecordedResultResponseBuilder"/> or <see cref="RequestNotFoundResponseBuilder"/> /// to build a <see cref="HttpWebResponse"/>. /// <para /> /// 3. Fire <see cref="OnMatch"/> /// <para /> /// 4. Honor <see cref="AllowReplayingRecordedRequestsMultipleTimes"/> and remove the matched /// <see cref="RecordedRequest"/> from <see cref="RecordedRequests"/> /// <para /> /// 5. Return the <see cref="HttpWebResponse"/>. aka Profit! /// </summary> public HttpWebResponse BuildResponse(InterceptedRequest intercepted) { lock (_buildResponseLock) { var matchedRecordedRequest = RecordedRequests .FirstOrDefault(recorded => MatchingAlgorithm(intercepted, recorded)); try { var response = null != matchedRecordedRequest ? RecordedResultResponseBuilder(matchedRecordedRequest, intercepted) : RequestNotFoundResponseBuilder(intercepted); OnMatch?.Invoke(matchedRecordedRequest, intercepted, response, null); return(response); } catch (Exception e) { OnMatch?.Invoke(matchedRecordedRequest, intercepted, null, e); throw; } finally { if (!AllowReplayingRecordedRequestsMultipleTimes && null != matchedRecordedRequest) { RecordedRequests.Remove(matchedRecordedRequest); } } } }
/// <inheritdoc /> public override WebResponse GetResponse() { HttpWebResponse passThroughShadowCopy = null; var interceptedRequest = new InterceptedRequest { RequestPayload = new RecordedStream( _requestStream.ToArray(), this), HttpWebRequest = this, HttpWebResponseCreator = new HttpWebResponseInterceptorCreator(RequestUri, Method, AutomaticDecompression), PassThroughResponse = () => { // if we are going to pass through - we need to use the base.GetRequest // to copy over the request stream (as well as set some additional headers like Content-Length) if (_requestStream.ToArray().Length > 0) { using (var requestStream = base.GetRequestStream()) new MemoryStream(_requestStream.ToArray()).WriteTo(requestStream); } // save the pass through so we'll know if _responseCreator // returned that to us - if so we don't want to try and // perform any initialization passThroughShadowCopy = (HttpWebResponse)base.GetResponse(); return(passThroughShadowCopy); } }; var response = _responseCreator(interceptedRequest); if (response == passThroughShadowCopy) { // short circuit return(passThroughShadowCopy); } // set response to HttpWebRequest's internal field ReflectionExtensions.SetField(this, "_HttpResponse", response); // wire up cookies - static void CookieModule.OnReceivedHeaders(HttpWebRequest) var cookieModuleType = typeof(HttpWebRequest).Assembly.GetType("System.Net.CookieModule"); // ReSharper disable once PossibleNullReferenceException cookieModuleType .GetMethod("OnReceivedHeaders", BindingFlags.Static | BindingFlags.NonPublic) .Invoke(null, new object[] { this }); return(response); }
/// <remarks> /// This is static so it can be referenced in constructor chaining /// </remarks> private static HttpWebResponse DefaultRequestNotFoundResponseBuilder( InterceptedRequest interceptedRequest, RequestNotFoundBehavior behavior) { switch (behavior) { case RequestNotFoundBehavior.PassThrough: return(interceptedRequest.PassThroughResponse()); case RequestNotFoundBehavior.Return404: return(interceptedRequest .HttpWebResponseCreator.Create( $"Request not found in {nameof(RecordedRequests)}", HttpStatusCode.NotFound)); default: throw new InvalidEnumArgumentException( $"Don't know how to handle behavior [{Enum.GetName(typeof(RequestNotFoundBehavior), behavior)}]. " + $"This is a bug in the {nameof(HttpWebRequestWrapper)} library."); } }
private HttpWebResponse DefaultRecordedResultResponseBuilder( RecordedRequest recordedRequest, InterceptedRequest interceptedRequest) { var headers = new WebHeaderCollection(); if (null != recordedRequest.ResponseHeaders) { headers.Add(recordedRequest.ResponseHeaders); } if (recordedRequest.TryGetResponseException(out var recordedException)) { // throw the recorded exception and let it bubble up throw recordedException; } return(interceptedRequest.HttpWebResponseCreator.Create( recordedRequest.ResponseBody.ToStream(), recordedRequest.ResponseStatusCode, headers)); }