Reading ASP.NET Response Header

  • Thread starter Thread starter _jpg_
  • Start date Start date
J

_jpg_

Hi,

I need to read (& store) all the custom response headers in an
HttpResponse. I am writing an HttpModule and hence do not know what
headers could have been added (but need to cache them for later use).
The only relevant methods that I can see are
AppendHeader/AddHeader(string, string) and ClearHeaders() both of
which are obviously useless to me. Is there any way of reading the
custom headers?

I also considered replacing the HttpResponse object with my own
wrapper that just passes me the headers which I can add later, but
HttpContext.Response is read-only.

Surely this should be possible?

Thanks

jpg

ps. I have actually got it working currently, I am using reflection to
'bypass' the fact that the _customHeaders field is private, although
this is obviously not the best way to do it.
 
_jpg_ said:
Hi,

I need to read (& store) all the custom response headers in an
HttpResponse. I am writing an HttpModule and hence do not know what
headers could have been added (but need to cache them for later use).
The only relevant methods that I can see are
AppendHeader/AddHeader(string, string) and ClearHeaders() both of
which are obviously useless to me. Is there any way of reading the
custom headers?

Do you only mean the custom headers, or do you need to get all of them?
Also, do you need to get at headers added by someone else's code?

If all you need is custom headers, and if you don't need them from someone
else's code, then I'd suggest you create methods to replace
AppendHeader/AddHeader and ClearHeaders. The methods would capture the
custom headers and then call Response.Append/Add/ClearHeaders.

Surely this should be possible?

Maybe. Note that you can't get at all of the headers, since they don't
actually exist anywhere until after the request is complete over. And even
then they don't exist as a collection or anything.
ps. I have actually got it working currently, I am using reflection to
'bypass' the fact that the _customHeaders field is private, although
this is obviously not the best way to do it.

This method will break as soon as they change their implementation. And if I
were them, I'd change the implementation just out of spite, knowing that
someone is poking around in my internals. HttpContext is even sealed. That
should be a hint to you...
 
Ideally I would like all the headers, or be able to set whatever I need
to so that I can modify a response object to recreate whatever the
previous one would have.

However, I cannot even see how I can get the custom headers that users'
code has added (via the Add/AppendHeader methods).

I cannot replace the Append/Add/ClearHeaders methods because to do that
I would need to replace the response object within the httpcontext (with
my wrapper), and this is readonly. I could provide my own methods on a
completely different object, but as I'm an HttpModule this is awkward,
and the whole point is that the developer does not need to change his
code.

The current caching modules must cache headers too, it's just that I
believe as they are in the same assembly they call a load of internal
methods.

I know my reflection method is bad but I cannot currently see any other
way around it.
 
_jpg_ said:
Ideally I would like all the headers, or be able to set whatever I need
to so that I can modify a response object to recreate whatever the
previous one would have.

I believe the technical term for this is "SOL". :-(

I have written an HttpModule which can capture the complete request and
response - except for the response headers! When I got to that point in the
code, I found that they literally do not exist as a collection, and do not
exist in any fashion until after the request is completely over. Instead,
ASP.NET produces its headers by calling methods on a class provided by the
hosting environment.

Now, there's your one hope. If your code has to work in the completely
general case, give up now and save yourself the trouble. But if you can run
your code under your own host (i.e., your own web server), then you can
produce a hack to make this happen. I managed to do this by hacking a
version of Microsoft's Cassini web server (a part of the Web Matrix project
at http://asp.net/webmatrix/default.aspx?tabIndex=4&tabId=46). As it turns
out, this was a fairly nasty hack, involving the server setting something in
one of the server variables for the HttpModule to read to pass back to a
static method in the server - it was pretty gross.

Under no circumstances would I consider such a hack suitable for any
production purpose. For any such purpose, I'd say, "sorry, find another way
to do it". For instance, you might be better off writing a network sniffer
or a custom proxy server than to screw around with private fields which are
as likely as not to change in the next .n release, or even on a service pack
release. "private" really means, "none of your business".

Good Luck. You'll need it.
 
Ok thanks for your help - my solution cannot require a modified web
server, which seems to me like more of a hack than mine!

I believe that the best solution for me will be to clone the whole
HttpResponse object (using reflection), and then clone it back over the
top of the new one. This should at least mean small changes such as
field renaming won't break it (yes I know calls to external
methods/deeper objects still could). I could support only specific
versions of the framework - and this method will be fine for all the
existing versions.

If Microsoft manage to break this down the line there are quite a few
other classes that I could use looking at the OutputCacheModule - none
of which are actually public again :-( It's really starting to annoy me
how closed the .NET api is compared to J2SE. Most of the classes seem to
be internal, as well as the amount they have sealed...

thanks
 
_jpg_ said:
Ok thanks for your help - my solution cannot require a modified web
server, which seems to me like more of a hack than mine!

I believe that the best solution for me will be to clone the whole
HttpResponse object (using reflection), and then clone it back over the
top of the new one. This should at least mean small changes such as
field renaming won't break it (yes I know calls to external
methods/deeper objects still could). I could support only specific
versions of the framework - and this method will be fine for all the
existing versions.

My immediate reaction is "you must be crazy". After calming down and
thinking about it for a while, I've decided to stick with my immediate
reaction.

It sounds like the problem you were asked to solve was, "get me all the
response headers for all the requests sent to this web site". It seems to me
that the solution is to "get the response headers from where they're meant
to be seen - in the HTTP header of the response". It would take a change in
the HTTP protocol to break _that_ code, whereas it would take only a sneeze
to break yours.
 
I agree this would be the best place to retrieve them, however I must
store them & issue a redirect, and if they have already been sent then I
am too late. I can only achieve this if all requests go through some
kind of proxy, which is very likely to not make it transparent to the
asp.net pages.

I imagine I could do it if I implemented the whole thing in a ISAPI
filter, which I may look at, but it seems stupid to me that I can't do
it in the framework itself.

Why do you see the reflection approach as such a problem if it is always
bound to a specific version of System.Web.dll? Updating my code for the
next release would not be a problem.

jpp
 
Back
Top