Monday, December 22, 2008

A workaround!

So there exists *one* way and one way only to safely set the Range header when using 64bit indices. This method was found with the help of NotZhila on #mono:

MethodInfo method = typeof(WebHeaderCollection).GetMethod
(
"AddWithoutValidate", BindingFlags.Instance | BindingFlags.NonPublic);

HttpWebRequest request
= (HttpWebRequest) WebRequest.Create ("http://www.example.com/file.exe");

long start = int32.MaxValue;
long end = int32.MaxValue + 100000;

string key = "Range";
string val = string.Format ("bytes={0}-{1}", start, end);

method.Invoke (request.Headers,
new object[] { key, val });


You need to call the protected method of the WebHeaderCollection class so you can add the "Range" header without being forced to go through the broken HttpWebRequestAddRange method. I tried about a half dozen more legitimate methods, but the API is so locked down that it was impossible.

For example, HttpWebRequest.Headers is a get/set property, but if you set a new collection, it checks to make sure "Range" isn't there, and then just copies the keys from your new collection into it's internal one and ignores the collection you just gave it. What this means is that:

CustomCollection c = new CustomCollection ();
request.Headers = c;
Console.WriteLine (request.Headers == c);

prints false.

Ouch.

Anyway, the hack works. If you need 64bit indices when downloading files via HttpWebRequest, here's your guaranteed working hack, on both Mono and MS.NET.

7 comments:

GrayShade said...

Method.Invoke might prove to be a little slow.

Alan said...

@GrayShade:
Compared to the time taken to download a few MB of data once the webrequest has been created, Method.Invoke could be 1000 times slower and I'd still not noticee difference ;)

knocte said...

Is there an open issue on MS Connect about this? :)

If yes, it would be nice to post the link. If not, it would be nice to file it.

Ryan said...

Couldn't you just inherit from the WebHeaderCollection class and add a public constructor which called the protected constructor? It should be less messy that way.

Alan said...

@Ryan:
Nope. If you read the last two paragraphs of my blogpost, i actually covered that issue. This hack is the *only* safe way around the bug in the framework design.

The only other option available is to write a proxying class. The idea of the proxy is this:

1) Create a WebRequest to "www.url.com".
2) Fill in any settings/headers you require into the WebRequest.
3) When you want to call WebRequest.GetResponse, instead create a socket which listens at 127.0.0.1:PORT and then make your webrequest go to 127.0.0.1:PORT.4
4) Read all the data from the socket.
5) Add on the "Range" header
6) Create another socket which contacts "www.url.com" and forward on the header data
7) Proxy data to/from the remote server through this socket

Obviously enough, this method is definitely less efficient, but it will work 100% of the time and doesn't involve nasty reflection hacks.

However, i think using reflection to call the protected member is perfectly OK as that is part of the public API and will not change. Calling a private or internal member would definitely be a no-go though.

cheap wow gold said...

It was not long cheap wow goldbefore some one knocked atwow gold cheap wow gold for salethe house-door and called, open the door, dear children, your mother is here, and has brought something back with her for each of you. But the little wow goldkids knew that it was the wolf, by the rough voice. We will wow power leveling not open the door, cried they, you are not our mother. She has a soft, pleasant voice, but your voice is rough, you are the wolf.

Then the wolf went World Of Warcraft Goldaway to a shopkeeper and bought himself a great cheapest wow goldlump of chalk, ate this and made gold4power.com his voice soft with it. The he came back, knocked at the door of the house, and world of warcraft gold salecalled, open the door, dear children, your mother is here and Cheapest Wow Goldhas brought something back with her for each of you.

gaohui said...

Have you noticed ed hardy Clothing that she is spending time with ed hardy sale one person in particular ed hardy and they seemed to come from ed hardy UK nowhere. When you ask how she ed hardy cheap knows them she becomes aloof and ed hardy Clothes disinterested. Is there someone's house ed hardy store she seems to be always going to? This edhardy.com could spell something is wrong with the christian audigier sale relationship. Is she taking trips, possibly day ed hardy dresses trips or small vacations without you? If ed hardy Polos she was doing this before you even ed hardy sandals got married or dated, then it may be okay, but if it is a recent ed hardy Jackets development then you may have problems.

Hit Counter