HttpWebRequest cookie with empty domain
Asked Answered
C

4

22

I have an ASP.NET MVC action that sends a GET request to another server via HttpWebRequest. I'd like to include all cookies in the original action's request in the new request. Some of the System.Web.HttpCookies in the original request have empty domain values (i.e. ""), which apparently doesn't cause any issues. When I create a System.Net.Cookie using the name, value, path, and domain of each of these cookies and add it to the request's CookieContainer, I get this error:

"System.ArgumentException: The parameter '{0}' cannot be an empty string. Parameter name: cookie.Domain"

Here's some code that will throw the same error (when the cookie is added):

var request = (HttpWebRequest)WebRequest.Create("http://www.whatever.com");
request.Method = "GET";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add ( new Cookie ( "MyCookieName", "MyCookieValue", "/", "") );

EDIT

I sort of fixed this by using "localhost" for the domain, instead of the null or empty string value from the original HttpCookie. So, why does an empty domain not work for the CookieContainer? And does HttpCookie use an empty value to signify localhost, or do I need to find another fix for this problem?

Chandachandal answered 16/12, 2010 at 17:24 Comment(4)
What exactly are you trying to do? Setting a cookie with the domain "localhost" on the container when you are sending the request to a different server will not work - the cookie will not be sent. If you can describe your scenario and what you are trying to achieve, maybe a better solution will reveal itself.Discoloration
It sounds like you're building a passthrough page -- probably for cross-site scripting? I'll post an answer below with some background information. For now check out en.wikipedia.org/wiki/HTTP_cookie to get how it works. The domain is very important.Acerate
@Angelisho has a good answer below that just works. I came to the same conclusion in my tests before finding his answer. Basically: request.Headers.Add(HttpRequestHeader.Cookie, "MyCookieName=MyCookieValue");Aeolotropic
In multi-tier networks, single sign-on authentication often uses cookies to store a session token. For an application to participate, it has to store that cookie either by caching within the application or by letting the client browser save a local cookie. In the latter case, a cookie with a local domain must be created to pass back to the browser, as in @BrainSlugs83's answer. Microsoft's haphazard cookie architecture complicates the procedure.Ratty
A
9

Disclaimer:

As stated earlier by @feroze, setting your cookies' domain to localhost is not going to work out so well for you. I'm assuming you're writing a helper that allows you to tunnel HTTP requests out to foreign domains. Note that this is not best practice and in a lot of cases is not needed (i.e. jQuery has a lot of cool cross-domain support built-in, also see the new CORS specification). But sometimes you may be stuck doing this (i.e. the external resource is XML only, and is on a server that doesn't support CORS).

Background Information on Cookie Domains and How They Work:

If you haven't already take a look at HTTP Cookie: Domain and Path on Wikipedia -- pretty much everything you need to know is in there.

When evaluating a cookie, the Domain and Path are taken into account by both the client (the "local" requester) and the web server (the "foreign" responder). When a client requests a resource, the client should only send cookies where those cookies match the Domain (or a more generic parent domain) and Path (or a more generic parent path) of the URI being requested.

Web browsers handle this correctly. If a web browser has a cookie for the domain "localhost" and you're requesting "google.com", for example, those cookies for the "localhost" domain won't be sent in the request to "google.com". -- In fact, most modern browsers won't just not send them, they'll completely ignore them in Set-Cookie response headers that they receive (these are called third-party cookies -- enabling the acceptance of third party cookies in your web browser is a huge privacy/security concern -- don't do it!).

It works in the other direction as well -- even though it's unlikely for a client to include a third party cookie in a request, if it does, the foreign web server is supposed to ignore it (and even some cookies for correct domains/paths, so as to prevent the infamous super-cookie issue. (i.e. The web server hosting "example.com" should ignore cookies belonging to its parent domain: ".com", because ".com" is a "public suffix")).

What You Should Do [if you have to]:

The course of action I recommend for you, is when you read in your client's cookies (I'm not an MVC guy, but in regular ASP.NET this would be in Request.Cookies), loop through them (make sure to filter out your own site's legitimate cookies, especially SessionId, etc -- or use Path properly so they never get sent to this page in the first place), then add them one at a time to the outgoing request's cookie collection, rewriting the domain to be "www.whatever.com" (per your example -- if you're doing this dynamically, load the URL into a new Uri() object and use the .Host property), and then set the Path to "/". -- This will build the "Cookie" header for the outgoing request to the foreign web server.

When that request returns to your server, you then need to check it's incoming response for new cookies -- those cookies can be repackaged and sent back down to your client in much the same type of loop as I illustrated in the previous paragraph, except you'll want to rewrite Host to be Request.Url.Host -- and you'll want to set path back to "/" unless the path to your passthru page is static (I'm guessing it isn't since you're using MVC) then you'd want to set it to Request.Url.AbsolutePath for instance.

Happy Coding!

EDIT: Also, you'll want to set the X-Forwarded-For tag of the outgoing request, so that the website you're calling doesn't think your web server is one single client that's been spamming the crap out of them.

Acerate answered 14/10, 2012 at 5:11 Comment(0)
G
5

Not sure it solves your problem. But to add cookies without the "Domain" property you must add to the headers the cookies using HttpRequestHeader.Cookie as follows.

request.Headers.Add(HttpRequestHeader.Cookie, "Your cookies...");

Hope it helps!

General answered 24/8, 2016 at 5:9 Comment(2)
I found this was the only way to make a cookie just work when making a web request, without having to try and guess the path or domain. Looks like you found the same thing.Aeolotropic
Awesome! Life saver!Ecosphere
S
3

Some background

This occurs because CookieContainer is client-side container designed to be reused across multiple HttpWebRequest. Reusing it provides the expected cookie behavior that cookies set by the remote host are sent back with every subsequent HttpWebRequests targeted at the same host.

As a result of the reuse, a CookieContainer might actually contain cookies from multiple request and\or hosts.

So, in order to determine which of the cookies in the container need to be sent with a particular HttpWebRequest to some host (domain), CookieContainer examines the Domain and the Path property.

That's why a Cookie in a CookieContainer needs to have a valid Domain.

Conversely, on the server-side cookies are delivered via a different type, CookieCollection which a simple list of cookies with no extra logic.


Specifically, in your case, while copying cookies from the CookieCollection to the CookieContainer you need to set the Domain property of every cookie to the domain your are going to forward the request to, so that HttpWebRequest will know to include the cookies while sending the request.

Spirochaetosis answered 28/5, 2013 at 22:56 Comment(0)
A
-1

You are trying to get cookies sent to localhost, right?

Why don't you do something like this where you give your own machine a real name:

  1. Edit your hosts file and add a line "127.0.0.1 myname.com"
  2. Test using myname.com - which is actually your localhost.

Your browser or app will not know the difference and send cookies to myname.com if that is where the cookie belongs.

Detailed info:

  1. The Hosts file on windows is located at C:\Windows\System32\drivers\etc\hosts
Attrahent answered 23/2, 2011 at 10:4 Comment(2)
You can't have an empty domain, because then which domain would the cookie be sent to?Attrahent
A cookie with an empty domain is supposed to take on the domain of the service it's being sent to.Ratty

© 2022 - 2024 — McMap. All rights reserved.