Introduction to the relationships and differences between HttpResponse Output OutputStream and Filter

  • 2020-05-17 05:22:11
  • OfStack

This code is often seen on the Internet

HttpResponse response = HttpContext.Current.Response;
response.Filter = new PageFilter(response.Filter);

To intercept the output stream, I also make a similar thing, such as asp.net js merged compression, now I also say what these several things are, we need to be familiar with asp.net life cycle, if not familiar with the friends suggest to look at ASP.NET request processing process ASP.NET pipeline and application life cycle

First let's take a look at the source code for these three properties:


public TextWriter Output 
{ 
get 
{ 
return this._writer; 
} 
set 
{ 
this._writer = value; 
} 
} 


public Stream OutputStream 
{ 
get 
{ 
if (!this.UsingHttpWriter) 
{ 
throw new HttpException(SR.GetString("OutputStream_NotAvail")); 
} 
return this._httpWriter.OutputStream; 
} 
} 



public Stream Filter 
{ 
get 
{ 
if (this.UsingHttpWriter) 
{ 
return this._httpWriter.GetCurrentFilter(); 
} 
return null; 
} 
set 
{ 
if (!this.UsingHttpWriter) 
{ 
throw new HttpException(SR.GetString("Filtering_not_allowed")); 
} 
this._httpWriter.InstallFilter(value); 
IIS7WorkerRequest request = this._wr as IIS7WorkerRequest; 
if (request != null) 
{ 
request.ResponseFilterInstalled(); 
} 
} 
}

We see that both Filter and OutputStream use a property called UsingHttpWriter. How is this property defined

private bool UsingHttpWriter 
{ 
get 
{ 
return ((this._httpWriter != null) && (this._writer == this._httpWriter)); 
} 
}

From this property we know that _writer and _httpWriter are actually the same thing, and their type is HttpWriter, while HttpWriter inherits from TextWriter. Now we can explain that Output is just _httpWriter, and OutputStream is the OutputStream property of _httpWriter. The main code for class HttpWriter is as follows

public Stream OutputStream 
{ 
get 
{ 
return this._stream; 
} 
} 


internal HttpWriter(HttpResponse response) : base(null) 
{ 
this._response = response; 
this._stream = new HttpResponseStream(this); 
this._buffers = new ArrayList(); 
this._lastBuffer = null; 
this._charBuffer = (char[]) s_Allocator.GetBuffer(); 
this._charBufferLength = this._charBuffer.Length; 
this._charBufferFree = this._charBufferLength; 
this.UpdateResponseBuffering(); 
} 


internal HttpResponseStream(HttpWriter writer) 
{ 
this._writer = writer; 
}

HttpResponse calls the InstallFilter method of the HttpWriter class in the Filter property setting, and gets the GetCurrentFilter that calls the class

internal void InstallFilter(Stream filter) 
{ 
if (this._filterSink == null) 
{ 
throw new HttpException(SR.GetString("Invalid_response_filter")); 
} 
this._installedFilter = filter; 
} 

internal Stream GetCurrentFilter() 
{ 
if (this._installedFilter != null) 
{ 
return this._installedFilter; 
} 
if (this._filterSink == null) 
{ 
this._filterSink = new HttpResponseStreamFilterSink(this); 
} 
return this._filterSink; 
}

From the above code, we can know that the output stream of HttpResponse is the stream set by Filter property, that is, the output stream of HttpResponse's Output and OutputStream properties is from the stream in Filter. Let's see when _writer, _httpWriter are initialized. There is one method in HttpResonse

internal void InitResponseWriter() 
{ 
if (this._httpWriter == null) 
{ 
this._httpWriter = new HttpWriter(this); 
this._writer = this._httpWriter; 
} 
} 

This method is called by ProcessRequestInternal of HttpRuntime

private void ProcessRequestInternal(HttpWorkerRequest wr) 
{ 
HttpContext context; 
try 
{ 
context = new HttpContext(wr, false); 
} 
catch 
{ 
wr.SendStatus(400, "Bad Request"); 
wr.SendKnownResponseHeader(12, "text/html; charset=utf-8"); 
byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>"); 
wr.SendResponseFromMemory(bytes, bytes.Length); 
wr.FlushResponse(true); 
wr.EndOfRequest(); 
return; 
} 
wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context); 
Interlocked.Increment(ref this._activeRequestCount); 
HostingEnvironment.IncrementBusyCount(); 
try 
{ 
try 
{ 
this.EnsureFirstRequestInit(context); 
} 
catch 
{ 
if (!context.Request.IsDebuggingRequest) 
{ 
throw; 
} 
} 
context.Response.InitResponseWriter(); 
IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context); 
if (applicationInstance == null) 
{ 
throw new HttpException(SR.GetString("Unable_create_app_object")); 
} 
if (EtwTrace.IsTraceEnabled(5, 1)) 
{ 
EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, applicationInstance.GetType().FullName, "Start"); 
} 
if (applicationInstance is IHttpAsyncHandler) 
{ 
IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance; 
context.AsyncAppHandler = handler2; 
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context); 
} 
else 
{ 
applicationInstance.ProcessRequest(context); 
this.FinishRequest(context.WorkerRequest, context, null); 
} 
} 
catch (Exception exception) 
{ 
context.Response.InitResponseWriter(); 
this.FinishRequest(wr, context, exception); 
} 
}


Related articles: