I'm using this enhanced version of WebClient to login in a site:
public class CookieAwareWebClient : WebClient
{
public CookieAwareWebClient()
{
CookieContainer = new CookieContainer();
}
public CookieContainer CookieContainer { get; private set; }
protected override WebRequest GetWebRequest(Uri address)
{
var request = (HttpWebRequest)base.GetWebRequest(address);
request.CookieContainer = CookieContainer;
return request;
}
}
And this way I send cookie to the site:
using (var client = new CookieAwareWebClient())
{
var values = new NameValueCollection
{
{ "username", "john" },
{ "password", "secret" },
};
client.UploadValues("http://example.com//dl27929", values);
// If the previous call succeeded we now have a valid authentication cookie
// so we could download the protected page
string result = client.DownloadString("http://domain.loc/testpage.aspx");
}
But when I run my program and capture the traffic in Fiddler I get 302 status code. I tested the request in Fiddler this way and everything is OK and I get the status code of 200.
The request in the Fiddler:
GET http://example.com//dl27929 HTTP/1.1
Cookie: username=john; password=secret;
Host: domain.loc
And here is the request sending by the application:
POST http://example.com//dl27929 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: www.domain.loc
Content-Length: 75
Expect: 100-continue
Connection: Keep-Alive
As you can see it doesn't send the cookie.
Any idea?
Everything works fine, just I forgot to set the cookie, Thanks Scott:
client.CookieContainer.SetCookies(new Uri("http://example.com//dl27929"), "username=john; password=secret;");
Related
fiddler settings:
Url
http://localhost:8080/lzp/servRoot (post)
Headers
User-Agent: Fiddler
Host: localhost:8080
Content-Length: 86
Content-Type: application/x-www-form-urlencoded
RequestBody
className=com.lzp.service.UserInfoService&methodName=login&user_name=123&user_pwd=123
And response
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Content-Type: text/json;charset=gbk
Transfer-Encoding: chunked
{"msg":false}
It returns {"msg":false} using fiddler.
Here is my code using RestSharp.
RestClient client = new RestClient("http://localhost:8080");
RestRequest request = new RestRequest("lzp/servRoot", Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("className", "com.lzp.service.UserInfoService");
request.AddParameter("methodName", "login");
request.AddParameter("user_name", "123");
request.AddParameter("user_pwd", "123");
var response = client.Execute<TestResultModel>(request);
var res = response.Data;
and the TestResultModel:
public class TestResultModel
{
public string msg { get; set; }
}
Why can't I get deserialize response data?
My question is how can I do POST request, next get cookie from that request and set it to the next request for example GET type in C#? Please for example code.
I had tried a lot of times, for example by CookieAwareWebClient method but it not working:
public class CookieAwareWebClient : WebClient
{
public CookieContainer CookieContainer { get; set; }
public CookieAwareWebClient()
: base()
{
CookieContainer = new CookieContainer();
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
HttpWebRequest webRequest = request as HttpWebRequest;
if (webRequest != null)
{
webRequest.CookieContainer = CookieContainer;
}
return request;
}
}
What I need? I need to login by POST requests and next do for example 10-20 request POST/GET by the authenticate cookie from first request (login)
I'm doing it by this:
//Create an instance of your new CookieAware Web Client
using (var client = new CookieAwareWebClient())
{
//Authenticate (username and password can be either hard-coded or pulled from a settings area)
var values = new NameValueCollection{{ "UserName", username },{ "Password", password }};
client.UploadValues(new Uri("http://www.yourdomain.com/Account/LogOn/"), "POST", values);
client.UploadString(new Uri("http://www.yourdomain.com/Secure/YourSecureMethod"),
"POST", "Example Message");
}
But I cant set this cookie to my next requests (next reauest creating thier own NEW non-authenticated cookies)
I am trying to emulate the process of accepting a trade offer in steam. I have asked steam support and the confirm that this action is allowed as long as I do not disrupt their service to other players.
So here is the details:
The URL for accepting a trade offer is https://steamcommunity.com/tradeoffer/OfferID/accept
Here is their ajax code for doing so
return $J.ajax(
{
url: 'https://steamcommunity.com/tradeoffer/' + nTradeOfferID + '/accept',
data: rgParams,
type: 'POST',
crossDomain: true,
xhrFields: { withCredentials: true }
}
Here is the headers i tracked using IE10
Request POST /tradeoffer/xxxxxxx/accept HTTP/1.1
Accept */*
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Referer http://steamcommunity.com/tradeoffer/xxxxxxx/
Accept-Language en-CA
Origin http://steamcommunity.com
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
Host steamcommunity.com
Content-Length 51
DNT 1
Connection Keep-Alive
Cache-Control no-cache
The post body:
sessionid=SESSIONID&tradeofferid=OfferID
Cookie:
Sent sessionid SessionID
Sent __utmc XXXXX
Sent steamLogin XXXXX
Sent webTradeEligibility XXXXXXX
Sent Steam_Language XXXXXXX
Sent timezoneOffset XXXXXXXX
Sent __utma XXXXXXXXXXXXX
Sent __utmz XXXXXXXXXXXXX
Sent steamMachineAuth XXXXXXXXXXXXX
Sent strInventoryLastContext XXXXXXXXX
Sent steamRememberLogin XXXXXXXXXXXX
Sent steamCC_XXXXXXXXXXXX XXXXXXX
Sent __utmb XXXXXXX
Sent tsTradeOffersLastRead XXXXXXX
the initiator of the request is XMLHttpRequest
In my code i did
public bool AcceptOffer(string offerID)
{
string path = "tradeoffer/" + offerID + "/";
//Simulate the browser opening the trade offer window
_steamWeb.Get(new Uri(WebAPI.SteamCommunity + path));
NameValueCollection data = new NameValueCollection();
data.Add("sessionid", _steamWeb.SessionID);
data.Add("tradeofferid", offerID);
string result = _steamWeb.Post(new Uri("https://steamcommunity.com/" + path + "accept"), data);
return true;
}
_steamWeb contains a cookie aware webclient which is used to do all the post/get requests
here are parts of the codes for the cookie aware webclient
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
if (request != null)
request.CookieContainer = _cookieContainer;
if (_lastPage != null)
request.Referer = _lastPage;
_lastPage = address.ToString();
return request;
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);//403 exception here
ReadCookies(response);
return response;
}
here is the headers that i am setting
void SetCommonHeaders(Uri uri)
{
_webClient.Headers[HttpRequestHeader.Accept] = "text/html, application/xhtml+xml, */*";
_webClient.Headers[HttpRequestHeader.AcceptLanguage] = "en-CA";
_webClient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded; charset=UTF-8";
_webClient.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
_webClient.Headers[HttpRequestHeader.Host] = uri.Host;
_webClient.Headers.Add("DNT", "1");
}
here are my cookie headers of the request i am sending
sessionid=XXXX;
steamMachineAuthXXXXX=XXXXXX;
steamLogin=XXXXXXX;
steamRememberLogin=XXXXXXXX;
Steam_Language=english;
webTradeEligibility=XXXXXXXXX;
steamCC_XXXXX=CA;
tsTradeOffersLastRead=XXXXXXXXX
I did not set those cookies manuelly, all of them are attened by GET requests to steamcommunity.com
I am pretty much sending the same request as the browser, but I am getting 403 Forbidden with my post. I have tried to set the X-Requested-With = XMLHttpRequest header but it is not helping. I see they are doing some credential thingy in the ajax call so am I suppose to do something too in my HttpWebRequest posts? Thanks
Problem solved, there are two things:
Keep alive header is not being send properly due to .NET bug
I encoded the sessionid twice
I'm using a web client that is cookie aware
public class CookieAwareWebClient : WebClient
{
public CookieContainer m_container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = m_container;
}
return request;
}
public CookieCollection Cookies(Uri domain)
{
return m_container.GetCookies(domain);
}
}
And making a few request to a web site that drops a set of cookies like this
webClient.Cookies(new Uri("http://<domain>.com")).Cast<Cookie>().ToArray()
{System.Net.Cookie[7]}
[0]: {UsrLocale=en_CA}
[1]: {Country=CA}
[2]: {$Version=1; ca_ord="UJMupexgTADsaH1yNi9eyA=="; $Path=/; $Domain=.<domain>.com}
[3]: {isLoggedin=false}
[4]: {cartCount=1}
[5]: {userPrefLanguage=en_CA}
The next request doesn't work as expected, and when I look in fiddler I see that cookie[2] hasn't been added to the headers. This one is pretty important by the looks of things. Does anyone know why it wouldn't be added to the request? All the others get popped in fine, and the domain I'm making a request to is a subdomain of the one listed in the cookie i.e. subDomain..com
var domain = new Uri("http://domain.com");
var webClient = new CookieAwareWebClient();
webClient.OpenRead("http://sub.domain.com");
webClient.RefreshCookies(domain);
webClient.UploadValues("http://sub.domain.com/browse/submit.jsp", new NameValueCollection
{
{"productId","prod610181"},
{"skuId","3431733"},
{"quantity","1"},
{"page","MAIN"}
});
webClient.RefreshCookies(domain);
webClient.OpenRead("http://sub.domain.com/shopping/bag.jsp");
webClient.RefreshCookies(domain);
var order = webClient.Cookies(new Uri("http://domain.com")).Cast<Cookie>().ToArray();
I'm trying to do some automated web requests and need to maintain a cookie from one to the next. I can see that I'm getting back the cookie I want from the initial response, but I can't attach it to the next request.
c# code
// response part
using (var wresp = (System.Net.HttpWebResponse)wrequest.GetResponse())
{
// respblob gets returned and is accessible to the next request
respblob.CookieList = new List<System.Net.Cookie>();
foreach (System.Net.Cookie cook in wresp.Cookies)
{
respblob.CookieList.Add(cook);
}
// ... more stuff not related to cookies
}
// next request part
var wrequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
wrequest.Method = "POST";
wrequest.ContentType = "application/x-www-form-urlencoded";
wrequest.CookieContainer = new System.Net.CookieContainer();
// request.CookieList contains one cookie as expected
// from the previous response
for (int j = 0; j < request.CookieList.Count; j++)
{
wrequest.CookieContainer.Add(request.CookieList[j]);
}
// .... write data to request body
// ... complete the request, etc
here is a recorded exchange for the two request/response actions.
request:
GET http://domain.com/Login.aspx?ReturnUrl=%2fDefault.aspx HTTP/1.1
Host: domain.com
Connection: Keep-Alive
response:
HTTP/1.1 200 OK
Date: Tue, 15 May 2012 17:17:52 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=zzz4fpb4alwi1du2yavx5tah; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 24408
...html content...
next request:
POST http://domain.com/Login.aspx?ReturnUrl=%2fDefault.aspx HTTP/1.1
Host: domain.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 979
Expect: 100-continue
__LASTFOCUS=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=viewstateclipped&__EVENTVALIDATION=validationclipped&ctl00%2524ContentPlaceHolder1%2524Login1%2524LoginButton=&ctl00%2524ContentPlaceHolder1%2524Login1%2524UserName=my.email%40example.com&ctl00%2524ContentPlaceHolder1%2524Login1%2524Password=myPassword
So even though the cookie exists in the HttpWebRequest CookieContainer, it doesn't get sent with the request. What am I doing wrong?
You should use the same CookieContainer instance for the both HttpWebRequest objects that you are using. simply create a CookieContainer instance once:
var cookieContainer = new CookieContainer();
and then have your both request objects use this instance:
var request1 = (HttpWebRequest)WebRequest.Create("http://example.com/url1");
// assign the cookie container for the first request
request1.CookieContainer = cookieContainer;
... go ahead and send the request and process the response
var request2 = (HttpWebRequest)WebRequest.Create("http://example.com/url2");
// reuse the same cookie container instance as the first request
request2.CookieContainer = cookieContainer;
... go ahead and send the request and process the response
Since you are using the same CookieContainer for the both requests, when the first request stores the cookie in this container, the cookie will be emitted alongside the second request automatically. This of course assumes that the second request is to the same domain as the first one.
Also since the cookie is a session cookie (HttpOnly flag) you cannot read its value from the client.