c# cookies httpwebrequest

c# - HttpWebResponse.Cookies empty a pesar del encabezado Set-Cookie(sin redirección)



httpwebrequest (7)

Al buscar otras respuestas, mejoré el manejo incorrecto de las cookies. A diferencia de esas respuestas, este maneja automáticamente todas las propiedades de las cookies (como expirado, seguro, etc.) y funciona con todo el rango de cookies (incluso cuando hay más de 1 cookie incorrecta).

Se implementa como método de extensión y se puede usar de la siguiente manera:

//... using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { request.FixCookies(response); //...

FixCookies() extensión FixCookies() :

using System; using System.Collections.Generic; using System.Net; namespace AG.WebHelpers { static public class ExtensionMethods { static public void FixCookies(this HttpWebRequest request, HttpWebResponse response) { for (int i = 0; i < response.Headers.Count; i++) { string name = response.Headers.GetKey(i); if (name != "Set-Cookie") continue; string value = response.Headers.Get(i); var cookieCollection = ParseCookieString(value, () => request.Host.Split('':'')[0]); response.Cookies.Add(cookieCollection); } } static private CookieCollection ParseCookieString(string cookieString, Func<string> getCookieDomainIfItIsMissingInCookie) { bool secure = false; bool httpOnly = false; string domainFromCookie = null; string path = null; string expiresString = null; Dictionary<string, string> cookiesValues = new Dictionary<string, string>(); var cookieValuePairsStrings = cookieString.Split('';''); foreach(string cookieValuePairString in cookieValuePairsStrings) { var pairArr = cookieValuePairString.Split(''=''); int pairArrLength = pairArr.Length; for (int i = 0; i < pairArrLength; i++) { pairArr[i] = pairArr[i].Trim(); } string propertyName = pairArr[0]; if (pairArrLength == 1) { if (propertyName.Equals("httponly", StringComparison.OrdinalIgnoreCase)) httpOnly = true; else if (propertyName.Equals("secure", StringComparison.OrdinalIgnoreCase)) secure = true; else throw new InvalidOperationException(string.Format("Unknown cookie property /"{0}/". All cookie is /"{1}/"", propertyName, cookieString)); continue; } string propertyValue = pairArr[1]; if (propertyName.Equals("expires", StringComparison.OrdinalIgnoreCase)) expiresString = propertyValue; else if (propertyName.Equals("domain", StringComparison.OrdinalIgnoreCase)) domainFromCookie = propertyValue; else if (propertyName.Equals("path", StringComparison.OrdinalIgnoreCase)) path = propertyValue; else cookiesValues.Add(propertyName, propertyValue); } DateTime expiresDateTime; if (expiresString != null) { expiresDateTime = DateTime.Parse(expiresString); } else { expiresDateTime = DateTime.MinValue; } if (string.IsNullOrEmpty(domainFromCookie)) { domainFromCookie = getCookieDomainIfItIsMissingInCookie(); } CookieCollection cookieCollection = new CookieCollection(); foreach (var pair in cookiesValues) { Cookie cookie = new Cookie(pair.Key, pair.Value, path, domainFromCookie); cookie.Secure = secure; cookie.HttpOnly = httpOnly; cookie.Expires = expiresDateTime; cookieCollection.Add(cookie); } return cookieCollection; } } }

Estoy luchando para descubrir qué está mal aquí. Estoy enviando información de inicio de sesión, puedo ver Set-Cookie en el encabezado con el valor correcto, pero la colección Cookies no se está llenando.

Esto es HTTPS, el inicio de sesión se redirige automáticamente, pero lo desactivé con AllowAutoRedirect = false para intentar solucionar este problema.

En esta captura de pantalla, puede ver fácilmente la información de depuración y que la cookie se debe establecer. Estoy configurando mi httpWebRequest.Cookie en una nueva CookieCollection.

HttpWebRequest httpRequest; CookieContainer reqCookies = new CookieContainer(); string url = "https://example.com"; string[] email = user.Split(''@''); email[0] = System.Web.HttpUtility.UrlEncode(email[0]); user = email[0] + "@" + email[1]; pass = System.Web.HttpUtility.UrlEncode(pass); string postData = "email=" + user + "&password=" + pass; byte[] byteData = Encoding.UTF8.GetBytes(postData); httpRequest = (HttpWebRequest)WebRequest.Create(url); httpRequest.Method = "POST"; httpRequest.Referer = url; httpRequest.CookieContainer = reqCookies; httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1003.1 Safari/535.19"; httpRequest.Accept = "text/html, application/xhtml+xml, */*"; httpRequest.ContentType = "application/x-www-form-urlencoded"; httpRequest.ContentLength = byteData.Length; using (Stream postStream = httpRequest.GetRequestStream()) { postStream.Write(byteData, 0, byteData.Length); postStream.Close(); } httpRequest.AllowAutoRedirect = false; HttpWebResponse b = (HttpWebResponse)httpRequest.GetResponse();

Intenté exactamente el mismo código de conexión a http://www.yahoo.com y las cookies se ponen en mi colección ... Argh ...

Aquí está el valor del encabezado Set-Cookie:

s = 541E2101-B768-45C8-B814-34A00525E50F; Dominio = ejemplo.com; Ruta = /; Versión = 1


Eso podría ser un poco tarde, pero puedes usar la función SetCookies

var cHeader = responce.Headers.Get("Set-Cookie"); var cookie = new CookieContainer(); cookie.SetCookies(new Uri("[...]"), cHeader);


La forma correcta de hacerlo es configurar el miembro CookieContainer antes de recuperar la respuesta:

var request = (HttpWebRequest)HttpWebRequest.Create(..); request.CookieContainer = new CookieContainer(); var response = request.GetResponse(); // ..response.Cookies will now contain the cookies sent back by the server.

No es necesario analizar manualmente SetCookie .


Parece que el encabezado de Set-Cookie enviado por el sitio web está mal formado (no en el formato típico que debería haber sido).

En tal caso, debe analizar la cookie de forma manual y CookieContainer al CookieContainer .

for (int i = 0; i < b.Headers.Count; i++) { string name = b.Headers.GetKey(i); string value = b.Headers.Get(i); if (name == "Set-Cookie") { Match match = Regex.Match(value, "(.+?)=(.+?);"); if (match.Captures.Count > 0) { reqCookies.Add(new Cookie(match.Groups[1].Value, match.Groups[2].Value, "/", "example.com")); } } }


Sé que esta pregunta es antigua, pero encontré un código que analiza correctamente un encabezado "Set-Cookie". Maneja las cookies separadas por comas y extrae el nombre, la fecha de vencimiento, la ruta, el valor y el dominio de cada cookie.

Este código funciona mejor que el propio analizador de cookies de Microsoft y esto es realmente lo que el analizador oficial de cookies debería estar haciendo. No tengo ni idea de por qué Microsoft no ha solucionado esto todavía, ya que es un problema muy común.

Aquí está el código original: http://snipplr.com/view/4427/

Lo estoy publicando aquí en caso de que el enlace se caiga en algún momento:

public static CookieCollection GetAllCookiesFromHeader(string strHeader, string strHost) { ArrayList al = new ArrayList(); CookieCollection cc = new CookieCollection(); if (strHeader != string.Empty) { al = ConvertCookieHeaderToArrayList(strHeader); cc = ConvertCookieArraysToCookieCollection(al, strHost); } return cc; } private static ArrayList ConvertCookieHeaderToArrayList(string strCookHeader) { strCookHeader = strCookHeader.Replace("/r", ""); strCookHeader = strCookHeader.Replace("/n", ""); string[] strCookTemp = strCookHeader.Split('',''); ArrayList al = new ArrayList(); int i = 0; int n = strCookTemp.Length; while (i < n) { if (strCookTemp[i].IndexOf("expires=", StringComparison.OrdinalIgnoreCase) > 0) { al.Add(strCookTemp[i] + "," + strCookTemp[i + 1]); i = i + 1; } else { al.Add(strCookTemp[i]); } i = i + 1; } return al; } private static CookieCollection ConvertCookieArraysToCookieCollection(ArrayList al, string strHost) { CookieCollection cc = new CookieCollection(); int alcount = al.Count; string strEachCook; string[] strEachCookParts; for (int i = 0; i < alcount; i++) { strEachCook = al[i].ToString(); strEachCookParts = strEachCook.Split('';''); int intEachCookPartsCount = strEachCookParts.Length; string strCNameAndCValue = string.Empty; string strPNameAndPValue = string.Empty; string strDNameAndDValue = string.Empty; string[] NameValuePairTemp; Cookie cookTemp = new Cookie(); for (int j = 0; j < intEachCookPartsCount; j++) { if (j == 0) { strCNameAndCValue = strEachCookParts[j]; if (strCNameAndCValue != string.Empty) { int firstEqual = strCNameAndCValue.IndexOf("="); string firstName = strCNameAndCValue.Substring(0, firstEqual); string allValue = strCNameAndCValue.Substring(firstEqual + 1, strCNameAndCValue.Length - (firstEqual + 1)); cookTemp.Name = firstName; cookTemp.Value = allValue; } continue; } if (strEachCookParts[j].IndexOf("path", StringComparison.OrdinalIgnoreCase) >= 0) { strPNameAndPValue = strEachCookParts[j]; if (strPNameAndPValue != string.Empty) { NameValuePairTemp = strPNameAndPValue.Split(''=''); if (NameValuePairTemp[1] != string.Empty) { cookTemp.Path = NameValuePairTemp[1]; } else { cookTemp.Path = "/"; } } continue; } if (strEachCookParts[j].IndexOf("domain", StringComparison.OrdinalIgnoreCase) >= 0) { strPNameAndPValue = strEachCookParts[j]; if (strPNameAndPValue != string.Empty) { NameValuePairTemp = strPNameAndPValue.Split(''=''); if (NameValuePairTemp[1] != string.Empty) { cookTemp.Domain = NameValuePairTemp[1]; } else { cookTemp.Domain = strHost; } } continue; } } if (cookTemp.Path == string.Empty) { cookTemp.Path = "/"; } if (cookTemp.Domain == string.Empty) { cookTemp.Domain = strHost; } cc.Add(cookTemp); } return cc; }


También encontré ese problema al leer Cookies en C # que fueron creadas por una aplicación C # ASP.NET ...;)

No estoy seguro de si tiene que ver con eso, pero descubrí que las dos cookies que están configuradas en mi caso están escritas en un solo encabezado de Set-Cookie, con la carga de cookie separada por comas. Así que adapté la solución de AppDeveloper para lidiar con este problema de cookies múltiples, así como para corregir el nombre / valor que mencioné en los comentarios.

private static void fixCookies(HttpWebRequest request, HttpWebResponse response) { for (int i = 0; i < response.Headers.Count; i++) { string name = response.Headers.GetKey(i); if (name != "Set-Cookie") continue; string value = response.Headers.Get(i); foreach (var singleCookie in value.Split('','')) { Match match = Regex.Match(singleCookie, "(.+?)=(.+?);"); if (match.Captures.Count == 0) continue; response.Cookies.Add( new Cookie( match.Groups[1].ToString(), match.Groups[2].ToString(), "/", request.Host.Split('':'')[0])); } } }


Use un CookieContainer como en esta respuesta . Lo que provocó que se me acercaran estos regex era una coma que expires=Tue, ...