public EvaluateResponseFilters ( IHttpResponse args, string connectionId, bool &isBodyRequired ) : byte[] | ||
args | IHttpResponse | |
connectionId | string | |
isBodyRequired | bool | |
return | byte[] |
public byte[] EvaluateResponseFilters( IHttpResponse args, string connectionId, out bool isBodyRequired )
{
isBodyRequired = false;
if (!_settings.FilteringEnabled.Value || ResponseFilters == null || ResponseFilters.Count() == 0)
{
return null;
}
lock (_whiteListedConnections)
{
if (_whiteListedConnections.Contains(connectionId))
{
_whiteListedConnections.Remove(connectionId);
return null;
}
}
string errorMessage = null;
_callbackList.Clear();
foreach (IResponseFilter filter in ResponseFilters.OrderBy(s => s.FilterSpeedType))
{
Func<IHttpResponse, string, byte[], byte[]> callback;
string filterText = filter.EvaluateFilter(args, connectionId, out callback);
if (!String.IsNullOrEmpty(filterText))
{
// Fail fast
errorMessage = filterText;
// Don't bother with the callbacks. The response has been filtered without the HTTP body.
// These types of filters are preferable over filters that require the body.
_callbackList.Clear();
break;
}
if (callback != null)
{
_callbackList.Add(callback);
}
}
if (!String.IsNullOrEmpty(errorMessage))
{
string body = String.Format("<html><head><title>Gallatin Proxy - Response Filtered</title></head><body>{0}</body></html>",
errorMessage);
return Encoding.UTF8.GetBytes(
String.Format("HTTP/{0} 200 OK\r\nConnection: close\r\nContent length: {1}\r\nContent-Type: text/html\r\n\r\n{2}",
args.Version,
body.Length,
body) );
}
// Clear the filters that require the HTTP body if there will be no body. Filters should
// check this themselves. This is a catch-all. Without this, a bad filter could hang the proxy
// by waiting for a body that will never arrive.
if (!args.HasBody)
{
_callbackList.Clear();
}
else
{
isBodyRequired = true;
}
return null;
}
public void VerifyResponseFilterWithCallbackWithBody([Values(true, false)] bool filterEnabled) { bool delegateHasBeenCalled = false; byte[] body = Encoding.UTF8.GetBytes( "this is the body" ); byte[] compressedBody = Compress( body ); byte[] outBody = Encoding.UTF8.GetBytes( "this is the modified body" ); Mock<IHttpHeaders> mockHeaders = new Mock<IHttpHeaders>(); mockHeaders.Setup( s => s["transfer-encoding"] ).Returns( "chunked" ); mockHeaders.Setup( s => s["content-encoding"] ).Returns( "gzip" ); Mock<ICoreSettings> settings = new Mock<ICoreSettings>(); settings.SetupGet(m => m.FilteringEnabled).Returns(filterEnabled); ProxyFilter filter = new ProxyFilter(settings.Object); List<IResponseFilter> filters = new List<IResponseFilter>(); Mock<IHttpResponse> response = new Mock<IHttpResponse>(); response.SetupAllProperties(); response.SetupGet( s => s.HasBody ).Returns( true ); response.SetupGet( s => s.Headers ).Returns( mockHeaders.Object ); Mock<IResponseFilter> mockFilter = new Mock<IResponseFilter>(); mockFilter.SetupGet( s => s.FilterSpeedType ).Returns( FilterSpeedType.Remote ); Func<IHttpResponse, string, byte[], byte[]> outParm = ( r, c, i ) => { delegateHasBeenCalled = true; Assert.That( r, Is.SameAs( response.Object ) ); Assert.That( c, Is.EqualTo( "connectionid" ) ); Assert.That( i, Is.EqualTo( body ), "This should be the uncompressed body" ); return outBody; }; mockFilter.Setup( s => s.EvaluateFilter( response.Object, "connectionid", out outParm ) ).Returns( null as string ); filters.Add( mockFilter.Object ); filter.ResponseFilters = filters; bool isBodyNeeded; byte[] filterResponse = filter.EvaluateResponseFilters( response.Object, "connectionid", out isBodyNeeded ); if (filterEnabled) { Assert.That(isBodyNeeded, Is.True); Assert.That(filterResponse, Is.Null); byte[] responseMessage = filter.EvaluateResponseFiltersWithBody(response.Object, "connectionid", compressedBody); Assert.That(responseMessage, Is.EqualTo(outBody)); mockHeaders.Verify(s => s.RemoveKeyValue("transfer-encoding", "chunked"), Times.Once()); mockHeaders.Verify(s => s.UpsertKeyValue("Content-Length", "25"), Times.Once()); mockHeaders.Verify(s => s.RemoveKeyValue("content-encoding", "gzip"), Times.Once()); mockHeaders.Verify(s => s.UpsertKeyValue("Content-Length", "16"), Times.Once(), "The header should have been updated with the uncompressed body size"); Assert.That(delegateHasBeenCalled, Is.True); } else { Assert.That(isBodyNeeded, Is.False); Assert.That(filterResponse, Is.Null); } }