[Mono-dev] mono WebResponse caching

Mark Lintner mlintner at sinenomine.net
Tue Jun 4 18:02:36 UTC 2013

We have noticed that parts of the Mono Web functionality are not yet implemented. We are hoping to be able to add some of these missing pieces. Caching of

HttpWebResponses is the first one we took a look at. It would appear that Microsoft takes advantage of the internet explorer caching. Since it would appear

that an HttpWebResponse is fully populated when it is returned from the cache and the only content in the urls that are cached are the bytes that come in on

the wire, Microsoft must return things from the cache at a very low level and and let the response populate the normal way. This did not seem possible to

emulate when I looked at mono. I also wanted to cache to a directory so that the urls can be inspected or deleted.

 After looking at the code for awhile I realized that I could save additional information from the response, ie: headercollection, cookiecontainer, Status

code etc in the same file as the responsestream. A response can be serialized but not all of it, most importantly the responsestream is not serialized. I

wrote a prototype with some helper functions, the only change to existing mono code would be in  HttpWebRequest.GetResponse. Before calling BeginGetResponse

I call a function that tries to retrieve the url from the cache. If it is not there, BeginGetResponse is called as normal, the response is grabbed from

EndGetResponse and passed to a method to insert into the cache. This insert method will open a filename in a directory designated as mono_cache with the name

produced by calling HttpUtility.Encode so it is a legal filename. Also you can only read from the responsestream once, which means that if read from it, save

it to a file, then the responsestream is no longer accessible from the WebResponse when it is returned to the calling code. If sream copy worked it could be

used here. One way to fix the problem is to call GetResponseStream(), read it to the end, which produces a string, then finally convert the string to bytes.

Then you can serialize the bytes to the open file, serialize the headercollection and ultimately individually add any field you want in the response when it

is retrieved from the cache, then close the file. Then create a new WebConnectionData instance and populate it with headers and all the relevent fields from

the old response, finally passing the bytes of data to a memory stream constructor and assign it to the WebConnectionData's stream member. Then I construct a

new HttpWebResponse, passing the WebConnectionData and other arguments which are taken from the existing request and the recently retrieved response. The

response is then returned to getResponse then finally to the calling code, good as new. Next time the url is requested the cached file is deserialized, one

member at a time then a WebConnectionData is setup and finally, a HttpWebResponse is constructed with the info read from the file, the WebConnectionData and

from the members of the new request. I concentrated on prototyping caching of HttpWebResponses. Only a simple cache algorithm, no Ftp, no File etc. No cache

aging etc. There are many other things that would have to be done for this to be usable.
  Using the prototype I requested www.google.com<http://www.google.com> and it took .1601419 sec to retrieve and cache it, including all the mechanics described above. The

second time returning it from the cache, building the HttpWebResponse took .0007671. This is a 288 times speedup. That kind of performance increase, from a

prototype that is not yet optimized, is compelling. I must add that I measured the same experiment with google under the .Net 4.5 implementation and the

speedup is 769x. Obviously thats something to work toward. Even falling short of that level of speedup, some implementation of response caching for mono

would greatly benefit the users who need better performance of services, rest etc.

So far this is the only mono code that would change to support caching,

from HttpWebRequest.cs:

  public override WebResponse GetResponse()


   WebResponse response = ResponseCache.TryRetrieve (this);

   if (response == null)


    WebAsyncResult result = (WebAsyncResult) BeginGetResponse (null, null);

    response = EndGetResponse (result);

    response.IsFromCache = false;

    HttpWebResponse response2 = ResponseCache.TryInsert ((HttpWebRequest)this, (HttpWebResponse)response);

    response.Close ();

    return response2;


   return response;


The code can stand some improvement. It is a prototype and it shows.  I have included the file ResponseCache.cs which the above

code hooks into. We were wondering whether anyone has tried to implement response caching before and whether there is any intent to in the future. What are

your thoughts about the approach described above and shown in the ResponseCache.cs file and the 3 other files I included. Bear in mind it

would be refactored so that it fit into the mono architecture a bit better, it needs to be generalized, different strategies for different concrete response

types need to be plugged in, configuration. and a plethora of things I missed. If you feel this approach has merit I can detail all that seperatly. If you

feel a different approach would work better, please let us know, in the end were looking to make mono more robust in some of the ways that are expected but

not yet implemented.
 The main thing I want to show here is how it is possible, to wedge a cache strategy into mono's request pipeline without changing or destabilizing

mono itself. The cache implementation could change also, which is one way that this is code falls short is it totally violates open-closed.  Is this a

viable approach? There would of course be much more to do, that I have not even mentioned here. Your comments would be appreciated.

The files can be found here.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ximian.com/pipermail/mono-devel-list/attachments/20130604/8abbd69e/attachment-0001.html>

More information about the Mono-devel-list mailing list