diff --git a/Leaf.xNet.Tests/~Http/HttpRequestTests.cs b/Leaf.xNet.Tests/~Http/HttpRequestTests.cs index 9d2ee15..dee12ce 100644 --- a/Leaf.xNet.Tests/~Http/HttpRequestTests.cs +++ b/Leaf.xNet.Tests/~Http/HttpRequestTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Leaf.xNet.Tests @@ -55,6 +56,18 @@ public void GetTest() } } + [TestMethod] + public void GetInconsistantCoookie() + { + const string url = "https://tinybuildgames.us7.list-manage.com/subscribe?u=7c5ba06b8b6710be2a32d1afc&id=5211b170b7"; + + using (var req = new HttpRequest()) + { + req.UserAgentRandomize(); + req.Get(url); + } + } + [TestMethod] public void PostTestFormEncoded() { diff --git a/Leaf.xNet/~Http/HttpResponse.cs b/Leaf.xNet/~Http/HttpResponse.cs index d101087..8cbe600 100644 --- a/Leaf.xNet/~Http/HttpResponse.cs +++ b/Leaf.xNet/~Http/HttpResponse.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -781,7 +782,7 @@ public Dictionary.Enumerator EnumerateHeaders() // Загружает ответ и возвращает размер ответа в байтах. - internal long LoadResponse(HttpMethod method, bool includeRedirectHeaders) + internal long LoadResponse(HttpMethod method, bool trackMiddleHeaders) { Method = method; Address = _request.Address; @@ -791,7 +792,7 @@ internal long LoadResponse(HttpMethod method, bool includeRedirectHeaders) KeepAliveTimeout = null; MaximumKeepAliveRequests = null; - if (includeRedirectHeaders && _headers.Count > 0) + if (trackMiddleHeaders && _headers.Count > 0) { foreach (var key in _headers.Keys) MiddleHeaders[key] = _headers[key]; @@ -916,7 +917,61 @@ private void ReceiveHeaders() string headerValue = header.Substring(separatorPos + 1).Trim(' ', '\t', '\r', '\n'); if (headerName.Equals("Set-Cookie", StringComparison.OrdinalIgnoreCase)) - Cookies.Set(_request.Address, headerValue); + { + if (_request.DontTrackCookies) + continue; + + // Отделяем Cross-domain cookie - если не делать, будет исключение. + // Родной парсинг raw-cookie плохо работает. + if (!headerValue.Contains("domain=")) + Cookies.Set(_request.Address, headerValue); + else + { + // Разделяем все key=value + var arguments = headerValue.Split(new [] {';'}, StringSplitOptions.RemoveEmptyEntries); + if (arguments.Length == 0) + continue; + + // Получаем ключ и значение самой Cookie + var keyValue = arguments[0].Split(new[] {'='}, 2); + var cookie = new Cookie(keyValue[0], keyValue.Length < 2 ? string.Empty : keyValue[1]); + + // Обрабатываем дополнительные ключи Cookie + for (int i = 1; i < arguments.Length; i++) + { + keyValue = arguments[i].Split(new[] {'='}, 2); + + // Обрабатываем ключи нерегистрозависимо + string key = keyValue[0].Trim().ToLower(); + string value = keyValue.Length < 2 ? null : keyValue[1].Trim(); + + switch (key) + { + case "expires": + if (!DateTime.TryParse(value, out var expires)) + continue; + + cookie.Expires = expires; + break; + + case "path": + cookie.Path = value; + break; + case "domain": + cookie.Domain = value; + break; + case "secure": + cookie.Secure = true; + break; + case "httponly": + cookie.HttpOnly = true; + break; + } + } + + Cookies.Set(cookie); + } + } else _headers[headerName] = headerValue; }