public void WebMetricsHttpModule_WillRewriteBodyEndTag() { // arrange var inputBuffer = Encoding.UTF8.GetBytes( $"const foo = \"</body>\";</body>{Environment.NewLine}</html>"); var httpApplication = new HttpApplication(); var httpContext = TestHttpContextFactory.Create(); var httpModule = new WebMetricsHttpModule(); httpModule.Init(httpApplication); var staticBindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static; var beginRequestKey = typeof(HttpApplication) .GetField("EventBeginRequest", staticBindingFlags) .GetValue(httpApplication); var preRequestHandlerExecuteKey = typeof(HttpApplication) .GetField("EventPreRequestHandlerExecute", staticBindingFlags) .GetValue(httpApplication); var postRequestHandlerExecuteKey = typeof(HttpApplication) .GetField("EventPostRequestHandlerExecute", staticBindingFlags) .GetValue(httpApplication); var instanceBindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance; var httpApplicationEvents = typeof(HttpApplication) .GetProperty("Events", instanceBindingFlags) .GetMethod .Invoke(httpApplication, null) as EventHandlerList; var initResponseWriter = typeof(HttpResponse) .GetMethod("InitResponseWriter", instanceBindingFlags); var typeOfHttpResponseStreamFilterSink = typeof(HttpApplication) .Assembly .GetTypes() .FirstOrDefault(e => e.FullName.StartsWith("System.Web.HttpResponseStreamFilterSink")); var filteringField = typeOfHttpResponseStreamFilterSink .GetField("_filtering", instanceBindingFlags); initResponseWriter.Invoke(HttpContext.Current.Response, null); var httpResponseStreamFilterSink = HttpContext.Current .Response .Filter; // execute httpApplicationEvents[beginRequestKey].DynamicInvoke(httpApplication, new EventArgs()); httpApplicationEvents[preRequestHandlerExecuteKey].DynamicInvoke(httpApplication, new EventArgs()); // swap in a stream we can observe var actualStream = new MemoryStream(); typeof(HtmlRewriteFilterStream) .GetField("_outputStream", instanceBindingFlags) .SetValue(HttpContext.Current.Response.Filter, actualStream); HttpContext.Current .Response .Filter .Write(inputBuffer, 0, inputBuffer.Length); filteringField.SetValue( httpResponseStreamFilterSink, true); HttpContext.Current .Response .Filter .Flush(); // verify Assert.AreNotEqual(0, actualStream.Length); var actualBuffer = new byte[actualStream.Length]; actualStream.Seek(0, SeekOrigin.Begin); actualStream.Read(actualBuffer, 0, actualBuffer.Length); var actualString = Encoding.UTF8.GetString(actualBuffer); if (!actualString.Contains("x4d-webmetrics")) { Assert.Fail("The resulting string did not contain expected content."); } if (!actualString.Contains("\"</body>\"")) { Assert.Fail("The resulting string did not contain expected quoted `</body>` text."); } }
public void WebMetricsHttpModule_WillNotRewriteUnsupportedContentType() { // arrange var inputBuffer = Encoding.UTF8.GetBytes( $"const foo = \"</body>\";</body>{Environment.NewLine}</html>"); var httpApplication = new HttpApplication(); var httpContext = TestHttpContextFactory.Create(); var httpModule = new WebMetricsHttpModule(); httpModule.Init(httpApplication); var staticBindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static; var beginRequestKey = typeof(HttpApplication) .GetField("EventBeginRequest", staticBindingFlags) .GetValue(httpApplication); var preRequestHandlerExecuteKey = typeof(HttpApplication) .GetField("EventPreRequestHandlerExecute", staticBindingFlags) .GetValue(httpApplication); var postRequestHandlerExecuteKey = typeof(HttpApplication) .GetField("EventPostRequestHandlerExecute", staticBindingFlags) .GetValue(httpApplication); var instanceBindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance; var httpApplicationEvents = typeof(HttpApplication) .GetProperty("Events", instanceBindingFlags) .GetMethod .Invoke(httpApplication, null) as EventHandlerList; var initResponseWriter = typeof(HttpResponse) .GetMethod("InitResponseWriter", instanceBindingFlags); var typeOfHttpResponseStreamFilterSink = typeof(HttpApplication) .Assembly .GetTypes() .FirstOrDefault(e => e.FullName.StartsWith("System.Web.HttpResponseStreamFilterSink")); var filteringField = typeOfHttpResponseStreamFilterSink .GetField("_filtering", instanceBindingFlags); initResponseWriter.Invoke(HttpContext.Current.Response, null); var httpResponseStreamFilterSink = HttpContext.Current .Response .Filter; // execute httpApplicationEvents[beginRequestKey].DynamicInvoke(httpApplication, new EventArgs()); HttpContext.Current.Response.ContentType = "image/png"; httpApplicationEvents[preRequestHandlerExecuteKey].DynamicInvoke(httpApplication, new EventArgs()); // swap in a stream we can observe var actualStream = new MemoryStream(); typeof(HtmlRewriteFilterStream) .GetField("_outputStream", instanceBindingFlags) .SetValue(HttpContext.Current.Response.Filter, actualStream); HttpContext.Current .Response .Filter .Write(inputBuffer, 0, inputBuffer.Length); filteringField.SetValue( httpResponseStreamFilterSink, true); HttpContext.Current .Response .Filter .Flush(); // verify var actualBuffer = new byte[actualStream.Length]; actualStream.Seek(0, SeekOrigin.Begin); actualStream.Read(actualBuffer, 0, actualBuffer.Length); var actualString = Encoding.UTF8.GetString(actualBuffer); Assert.AreEqual(inputBuffer.Length, actualBuffer.Length); for (int i = 0; i < actualBuffer.Length; i++) { if (inputBuffer[i] != actualBuffer[i]) { Assert.Fail($"Data at buffer position {i} did not match, expected:<{inputBuffer[i]}>, actual:<{actualBuffer[i]}>."); } } }