mscorlib(4.0.0.0) API with additions
CookieContainer.cs
1 using System.Collections;
5 using System.Text;
6 using System.Threading;
7 
8 namespace System.Net
9 {
11  [Serializable]
12  [global::__DynamicallyInvokable]
13  public class CookieContainer
14  {
16  [global::__DynamicallyInvokable]
17  public const int DefaultCookieLimit = 300;
18 
20  [global::__DynamicallyInvokable]
21  public const int DefaultPerDomainCookieLimit = 20;
22 
24  [global::__DynamicallyInvokable]
25  public const int DefaultCookieLengthLimit = 4096;
26 
27  private static readonly HeaderVariantInfo[] HeaderInfo = new HeaderVariantInfo[2]
28  {
29  new HeaderVariantInfo("Set-Cookie", CookieVariant.Rfc2109),
30  new HeaderVariantInfo("Set-Cookie2", CookieVariant.Rfc2965)
31  };
32 
33  private Hashtable m_domainTable = new Hashtable();
34 
35  private int m_maxCookieSize = 4096;
36 
37  private int m_maxCookies = 300;
38 
39  private int m_maxCookiesPerDomain = 20;
40 
41  private int m_count;
42 
43  private string m_fqdnMyDomain = string.Empty;
44 
49  [global::__DynamicallyInvokable]
50  public int Capacity
51  {
52  [global::__DynamicallyInvokable]
53  get
54  {
55  return m_maxCookies;
56  }
57  [global::__DynamicallyInvokable]
58  set
59  {
60  if (value <= 0 || (value < m_maxCookiesPerDomain && m_maxCookiesPerDomain != int.MaxValue))
61  {
62  throw new ArgumentOutOfRangeException("value", SR.GetString("net_cookie_capacity_range", "Capacity", 0, m_maxCookiesPerDomain));
63  }
64  if (value < m_maxCookies)
65  {
66  m_maxCookies = value;
67  AgeCookies(null);
68  }
69  m_maxCookies = value;
70  }
71  }
72 
75  [global::__DynamicallyInvokable]
76  public int Count
77  {
78  [global::__DynamicallyInvokable]
79  get
80  {
81  return m_count;
82  }
83  }
84 
89  [global::__DynamicallyInvokable]
90  public int MaxCookieSize
91  {
92  [global::__DynamicallyInvokable]
93  get
94  {
95  return m_maxCookieSize;
96  }
97  [global::__DynamicallyInvokable]
98  set
99  {
100  if (value <= 0)
101  {
102  throw new ArgumentOutOfRangeException("value");
103  }
104  m_maxCookieSize = value;
105  }
106  }
107 
113  [global::__DynamicallyInvokable]
114  public int PerDomainCapacity
115  {
116  [global::__DynamicallyInvokable]
117  get
118  {
119  return m_maxCookiesPerDomain;
120  }
121  [global::__DynamicallyInvokable]
122  set
123  {
124  if (value <= 0 || (value > m_maxCookies && value != int.MaxValue))
125  {
126  throw new ArgumentOutOfRangeException("value");
127  }
128  if (value < m_maxCookiesPerDomain)
129  {
130  m_maxCookiesPerDomain = value;
131  AgeCookies(null);
132  }
133  m_maxCookiesPerDomain = value;
134  }
135  }
136 
138  [global::__DynamicallyInvokable]
140  {
141  string domainName = IPGlobalProperties.InternalGetIPGlobalProperties().DomainName;
142  if (domainName != null && domainName.Length > 1)
143  {
144  m_fqdnMyDomain = "." + domainName;
145  }
146  }
147 
152  public CookieContainer(int capacity)
153  : this()
154  {
155  if (capacity <= 0)
156  {
157  throw new ArgumentException(SR.GetString("net_toosmall"), "Capacity");
158  }
159  m_maxCookies = capacity;
160  }
161 
171  public CookieContainer(int capacity, int perDomainCapacity, int maxCookieSize)
172  : this(capacity)
173  {
174  if (perDomainCapacity != int.MaxValue && (perDomainCapacity <= 0 || perDomainCapacity > capacity))
175  {
176  throw new ArgumentOutOfRangeException("perDomainCapacity", SR.GetString("net_cookie_capacity_range", "PerDomainCapacity", 0, capacity));
177  }
178  m_maxCookiesPerDomain = perDomainCapacity;
179  if (maxCookieSize <= 0)
180  {
181  throw new ArgumentException(SR.GetString("net_toosmall"), "MaxCookieSize");
182  }
183  m_maxCookieSize = maxCookieSize;
184  }
185 
193  public void Add(Cookie cookie)
194  {
195  if (cookie == null)
196  {
197  throw new ArgumentNullException("cookie");
198  }
199  if (cookie.Domain.Length == 0)
200  {
201  throw new ArgumentException(SR.GetString("net_emptystringcall"), "cookie.Domain");
202  }
203  StringBuilder stringBuilder = new StringBuilder();
205  if (!cookie.DomainImplicit && cookie.Domain[0] == '.')
206  {
207  stringBuilder.Append("0");
208  }
209  stringBuilder.Append(cookie.Domain);
210  if (cookie.PortList != null)
211  {
212  stringBuilder.Append(":").Append(cookie.PortList[0]);
213  }
214  stringBuilder.Append(cookie.Path);
215  if (!Uri.TryCreate(stringBuilder.ToString(), UriKind.Absolute, out Uri result))
216  {
217  throw new CookieException(SR.GetString("net_cookie_attribute", "Domain", cookie.Domain));
218  }
219  Cookie cookie2 = cookie.Clone();
220  cookie2.VerifySetDefaults(cookie2.Variant, result, IsLocalDomain(result.Host), m_fqdnMyDomain, set_default: true, isThrow: true);
221  Add(cookie2, throwOnError: true);
222  }
223 
224  private void AddRemoveDomain(string key, PathList value)
225  {
226  lock (m_domainTable.SyncRoot)
227  {
228  if (value == null)
229  {
230  m_domainTable.Remove(key);
231  }
232  else
233  {
234  m_domainTable[key] = value;
235  }
236  }
237  }
238 
239  internal void Add(Cookie cookie, bool throwOnError)
240  {
241  if (cookie.Value.Length > m_maxCookieSize)
242  {
243  if (throwOnError)
244  {
245  throw new CookieException(SR.GetString("net_cookie_size", cookie.ToString(), m_maxCookieSize));
246  }
247  }
248  else
249  {
250  try
251  {
252  PathList pathList;
253  lock (m_domainTable.SyncRoot)
254  {
255  pathList = (PathList)m_domainTable[cookie.DomainKey];
256  if (pathList == null)
257  {
258  pathList = new PathList();
259  AddRemoveDomain(cookie.DomainKey, pathList);
260  }
261  }
262  int cookiesCount = pathList.GetCookiesCount();
263  CookieCollection cookieCollection;
264  lock (pathList.SyncRoot)
265  {
266  cookieCollection = (CookieCollection)pathList[cookie.Path];
267  if (cookieCollection == null)
268  {
269  cookieCollection = new CookieCollection();
270  pathList[cookie.Path] = cookieCollection;
271  }
272  }
273  if (cookie.Expired)
274  {
275  lock (cookieCollection)
276  {
277  int num = cookieCollection.IndexOf(cookie);
278  if (num != -1)
279  {
280  cookieCollection.RemoveAt(num);
281  m_count--;
282  }
283  }
284  }
285  else if ((cookiesCount < m_maxCookiesPerDomain || AgeCookies(cookie.DomainKey)) && (m_count < m_maxCookies || AgeCookies(null)))
286  {
287  lock (cookieCollection)
288  {
289  m_count += cookieCollection.InternalAdd(cookie, isStrict: true);
290  }
291  }
292  }
293  catch (Exception ex)
294  {
295  if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
296  {
297  throw;
298  }
299  if (throwOnError)
300  {
301  throw new CookieException(SR.GetString("net_container_add_cookie"), ex);
302  }
303  }
304  }
305  }
306 
307  private bool AgeCookies(string domain)
308  {
309  if (m_maxCookies == 0 || m_maxCookiesPerDomain == 0)
310  {
311  m_domainTable = new Hashtable();
312  m_count = 0;
313  return false;
314  }
315  int num = 0;
316  DateTime dateTime = DateTime.MaxValue;
317  CookieCollection cookieCollection = null;
318  string text = null;
319  string text2 = null;
320  int num2 = 0;
321  int num3 = 0;
322  float num4 = 1f;
323  if (m_count > m_maxCookies)
324  {
325  num4 = (float)m_maxCookies / (float)m_count;
326  }
327  lock (m_domainTable.SyncRoot)
328  {
329  foreach (DictionaryEntry item in m_domainTable)
330  {
331  PathList pathList;
332  if (domain == null)
333  {
334  text2 = (string)item.Key;
335  pathList = (PathList)item.Value;
336  }
337  else
338  {
339  text2 = domain;
340  pathList = (PathList)m_domainTable[domain];
341  }
342  num2 = 0;
343  lock (pathList.SyncRoot)
344  {
345  foreach (CookieCollection value in pathList.Values)
346  {
347  num3 = ExpireCollection(value);
348  num += num3;
349  m_count -= num3;
350  num2 += value.Count;
351  DateTime dateTime2;
352  if (value.Count > 0 && (dateTime2 = value.TimeStamp(CookieCollection.Stamp.Check)) < dateTime)
353  {
354  text = text2;
355  cookieCollection = value;
356  dateTime = dateTime2;
357  }
358  }
359  }
360  int num5 = Math.Min((int)((float)num2 * num4), Math.Min(m_maxCookiesPerDomain, m_maxCookies) - 1);
361  if (num2 > num5)
362  {
363  Array array;
364  Array array2;
365  lock (pathList.SyncRoot)
366  {
367  array = Array.CreateInstance(typeof(CookieCollection), pathList.Count);
368  array2 = Array.CreateInstance(typeof(DateTime), pathList.Count);
369  foreach (CookieCollection value2 in pathList.Values)
370  {
371  array2.SetValue(value2.TimeStamp(CookieCollection.Stamp.Check), num3);
372  array.SetValue(value2, num3);
373  num3++;
374  }
375  }
376  Array.Sort(array2, array);
377  num3 = 0;
378  for (int i = 0; i < array.Length; i++)
379  {
380  CookieCollection cookieCollection4 = (CookieCollection)array.GetValue(i);
381  lock (cookieCollection4)
382  {
383  while (num2 > num5 && cookieCollection4.Count > 0)
384  {
385  cookieCollection4.RemoveAt(0);
386  num2--;
387  m_count--;
388  num++;
389  }
390  }
391  if (num2 <= num5)
392  {
393  break;
394  }
395  }
396  if (num2 > num5 && domain != null)
397  {
398  return false;
399  }
400  }
401  }
402  }
403  if (domain != null)
404  {
405  return true;
406  }
407  if (num != 0)
408  {
409  return true;
410  }
411  if (dateTime == DateTime.MaxValue)
412  {
413  return false;
414  }
415  lock (cookieCollection)
416  {
417  while (m_count >= m_maxCookies && cookieCollection.Count > 0)
418  {
419  cookieCollection.RemoveAt(0);
420  m_count--;
421  }
422  }
423  return true;
424  }
425 
426  private int ExpireCollection(CookieCollection cc)
427  {
428  lock (cc)
429  {
430  int count = cc.Count;
431  for (int num = count - 1; num >= 0; num--)
432  {
433  Cookie cookie = cc[num];
434  if (cookie.Expired)
435  {
436  cc.RemoveAt(num);
437  }
438  }
439  return count - cc.Count;
440  }
441  }
442 
447  public void Add(CookieCollection cookies)
448  {
449  if (cookies == null)
450  {
451  throw new ArgumentNullException("cookies");
452  }
453  foreach (Cookie cooky in cookies)
454  {
455  Add(cooky);
456  }
457  }
458 
459  internal bool IsLocalDomain(string host)
460  {
461  int num = host.IndexOf('.');
462  if (num == -1)
463  {
464  return true;
465  }
466  if (host == "127.0.0.1" || host == "::1" || host == "0:0:0:0:0:0:0:1")
467  {
468  return true;
469  }
470  if (string.Compare(m_fqdnMyDomain, 0, host, num, m_fqdnMyDomain.Length, StringComparison.OrdinalIgnoreCase) == 0)
471  {
472  return true;
473  }
474  string[] array = host.Split('.');
475  if (array != null && array.Length == 4 && array[0] == "127")
476  {
477  int i;
478  for (i = 1; i < 4; i++)
479  {
480  switch (array[i].Length)
481  {
482  case 3:
483  if (array[i][2] < '0' || array[i][2] > '9')
484  {
485  break;
486  }
487  goto case 2;
488  case 2:
489  if (array[i][1] < '0' || array[i][1] > '9')
490  {
491  break;
492  }
493  goto case 1;
494  case 1:
495  if (array[i][0] >= '0' && array[i][0] <= '9')
496  {
497  continue;
498  }
499  break;
500  }
501  break;
502  }
503  if (i == 4)
504  {
505  return true;
506  }
507  }
508  return false;
509  }
510 
518  [global::__DynamicallyInvokable]
519  public void Add(Uri uri, Cookie cookie)
520  {
521  if (uri == null)
522  {
523  throw new ArgumentNullException("uri");
524  }
525  if (cookie == null)
526  {
527  throw new ArgumentNullException("cookie");
528  }
529  Cookie cookie2 = cookie.Clone();
530  cookie2.VerifySetDefaults(cookie2.Variant, uri, IsLocalDomain(uri.Host), m_fqdnMyDomain, set_default: true, isThrow: true);
531  Add(cookie2, throwOnError: true);
532  }
533 
541  [global::__DynamicallyInvokable]
542  public void Add(Uri uri, CookieCollection cookies)
543  {
544  if (uri == null)
545  {
546  throw new ArgumentNullException("uri");
547  }
548  if (cookies == null)
549  {
550  throw new ArgumentNullException("cookies");
551  }
552  bool isLocalDomain = IsLocalDomain(uri.Host);
553  foreach (Cookie cooky in cookies)
554  {
555  Cookie cookie2 = cooky.Clone();
556  cookie2.VerifySetDefaults(cookie2.Variant, uri, isLocalDomain, m_fqdnMyDomain, set_default: true, isThrow: true);
557  Add(cookie2, throwOnError: true);
558  }
559  }
560 
561  internal CookieCollection CookieCutter(Uri uri, string headerName, string setCookieHeader, bool isThrow)
562  {
563  CookieCollection cookieCollection = new CookieCollection();
564  CookieVariant variant = CookieVariant.Unknown;
565  if (headerName == null)
566  {
567  variant = CookieVariant.Rfc2109;
568  }
569  else
570  {
571  for (int i = 0; i < HeaderInfo.Length; i++)
572  {
573  if (string.Compare(headerName, HeaderInfo[i].Name, StringComparison.OrdinalIgnoreCase) == 0)
574  {
575  variant = HeaderInfo[i].Variant;
576  }
577  }
578  }
579  bool isLocalDomain = IsLocalDomain(uri.Host);
580  try
581  {
582  CookieParser cookieParser = new CookieParser(setCookieHeader);
583  while (true)
584  {
585  Cookie cookie = cookieParser.Get();
586  if (cookie == null)
587  {
588  break;
589  }
590  if (ValidationHelper.IsBlankString(cookie.Name))
591  {
592  if (isThrow)
593  {
594  throw new CookieException(SR.GetString("net_cookie_format"));
595  }
596  }
597  else if (cookie.VerifySetDefaults(variant, uri, isLocalDomain, m_fqdnMyDomain, set_default: true, isThrow))
598  {
599  cookieCollection.InternalAdd(cookie, isStrict: true);
600  }
601  }
602  }
603  catch (Exception ex)
604  {
605  if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
606  {
607  throw;
608  }
609  if (isThrow)
610  {
611  throw new CookieException(SR.GetString("net_cookie_parse_header", uri.AbsoluteUri), ex);
612  }
613  }
614  foreach (Cookie item in cookieCollection)
615  {
616  Add(item, isThrow);
617  }
618  return cookieCollection;
619  }
620 
626  [global::__DynamicallyInvokable]
628  {
629  if (uri == null)
630  {
631  throw new ArgumentNullException("uri");
632  }
633  return InternalGetCookies(uri);
634  }
635 
636  internal CookieCollection InternalGetCookies(Uri uri)
637  {
638  bool isSecure = uri.Scheme == Uri.UriSchemeHttps;
639  int port = uri.Port;
640  CookieCollection cookieCollection = new CookieCollection();
641  List<string> list = new List<string>();
642  List<string> list2 = new List<string>();
643  string host = uri.Host;
644  list.Add(host);
645  list.Add("." + host);
646  int num = host.IndexOf('.');
647  if (num == -1)
648  {
649  if (m_fqdnMyDomain != null && m_fqdnMyDomain.Length != 0)
650  {
651  list.Add(host + m_fqdnMyDomain);
652  list.Add(m_fqdnMyDomain);
653  }
654  }
655  else
656  {
657  list.Add(host.Substring(num));
658  if (host.Length > 2)
659  {
660  int num2 = host.LastIndexOf('.', host.Length - 2);
661  if (num2 > 0)
662  {
663  num2 = host.LastIndexOf('.', num2 - 1);
664  }
665  if (num2 != -1)
666  {
667  while (num < num2 && (num = host.IndexOf('.', num + 1)) != -1)
668  {
669  list2.Add(host.Substring(num));
670  }
671  }
672  }
673  }
674  BuildCookieCollectionFromDomainMatches(uri, isSecure, port, cookieCollection, list, matchOnlyPlainCookie: false);
675  BuildCookieCollectionFromDomainMatches(uri, isSecure, port, cookieCollection, list2, matchOnlyPlainCookie: true);
676  return cookieCollection;
677  }
678 
679  private void BuildCookieCollectionFromDomainMatches(Uri uri, bool isSecure, int port, CookieCollection cookies, List<string> domainAttribute, bool matchOnlyPlainCookie)
680  {
681  for (int i = 0; i < domainAttribute.Count; i++)
682  {
683  bool flag = false;
684  bool flag2 = false;
685  PathList pathList;
686  lock (m_domainTable.SyncRoot)
687  {
688  pathList = (PathList)m_domainTable[domainAttribute[i]];
689  }
690  if (pathList == null)
691  {
692  continue;
693  }
694  lock (pathList.SyncRoot)
695  {
696  foreach (DictionaryEntry item in pathList)
697  {
698  string text = (string)item.Key;
699  if (uri.AbsolutePath.StartsWith(CookieParser.CheckQuoted(text)))
700  {
701  flag = true;
702  CookieCollection cookieCollection = (CookieCollection)item.Value;
703  cookieCollection.TimeStamp(CookieCollection.Stamp.Set);
704  MergeUpdateCollections(cookies, cookieCollection, port, isSecure, matchOnlyPlainCookie);
705  if (text == "/")
706  {
707  flag2 = true;
708  }
709  }
710  else if (flag)
711  {
712  break;
713  }
714  }
715  }
716  if (!flag2)
717  {
718  CookieCollection cookieCollection2 = (CookieCollection)pathList["/"];
719  if (cookieCollection2 != null)
720  {
721  cookieCollection2.TimeStamp(CookieCollection.Stamp.Set);
722  MergeUpdateCollections(cookies, cookieCollection2, port, isSecure, matchOnlyPlainCookie);
723  }
724  }
725  if (pathList.Count == 0)
726  {
727  AddRemoveDomain(domainAttribute[i], null);
728  }
729  }
730  }
731 
732  private void MergeUpdateCollections(CookieCollection destination, CookieCollection source, int port, bool isSecure, bool isPlainOnly)
733  {
734  lock (source)
735  {
736  for (int i = 0; i < source.Count; i++)
737  {
738  bool flag = false;
739  Cookie cookie = source[i];
740  if (cookie.Expired)
741  {
742  source.RemoveAt(i);
743  m_count--;
744  i--;
745  }
746  else
747  {
748  if (!isPlainOnly || cookie.Variant == CookieVariant.Plain)
749  {
750  if (cookie.PortList != null)
751  {
752  int[] portList = cookie.PortList;
753  foreach (int num in portList)
754  {
755  if (num == port)
756  {
757  flag = true;
758  break;
759  }
760  }
761  }
762  else
763  {
764  flag = true;
765  }
766  }
767  if (cookie.Secure && !isSecure)
768  {
769  flag = false;
770  }
771  if (flag)
772  {
773  destination.InternalAdd(cookie, isStrict: false);
774  }
775  }
776  }
777  }
778  }
779 
785  [global::__DynamicallyInvokable]
786  public string GetCookieHeader(Uri uri)
787  {
788  if (uri == null)
789  {
790  throw new ArgumentNullException("uri");
791  }
792  string optCookie;
793  return GetCookieHeader(uri, out optCookie);
794  }
795 
796  internal string GetCookieHeader(Uri uri, out string optCookie2)
797  {
798  CookieCollection cookieCollection = InternalGetCookies(uri);
799  string text = string.Empty;
800  string str = string.Empty;
801  foreach (Cookie item in cookieCollection)
802  {
803  text = text + str + item.ToString();
804  str = "; ";
805  }
806  optCookie2 = (cookieCollection.IsOtherVersionSeen ? ("$Version=" + 1.ToString(NumberFormatInfo.InvariantInfo)) : string.Empty);
807  return text;
808  }
809 
818  [global::__DynamicallyInvokable]
819  public void SetCookies(Uri uri, string cookieHeader)
820  {
821  if (uri == null)
822  {
823  throw new ArgumentNullException("uri");
824  }
825  if (cookieHeader == null)
826  {
827  throw new ArgumentNullException("cookieHeader");
828  }
829  CookieCutter(uri, null, cookieHeader, isThrow: true);
830  }
831  }
832 }
UriKind
Defines the kinds of T:System.Uris for the M:System.Uri.IsWellFormedUriString(System....
Definition: UriKind.cs:5
int Port
Gets the port number of this URI.
Definition: Uri.cs:617
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
The Cookie header, which specifies cookie data presented to the server.
static readonly string UriSchemeHttp
Specifies that the URI is accessed through the Hypertext Transfer Protocol (HTTP)....
Definition: Uri.cs:154
int Count
Gets the number of elements contained in the T:System.Collections.Generic.List`1.
Definition: List.cs:296
unsafe override string ToString()
Converts the value of this instance to a T:System.String.
StringComparison
Specifies the culture, case, and sort rules to be used by certain overloads of the M:System....
string AbsoluteUri
Gets the absolute URI.
Definition: Uri.cs:344
Definition: __Canon.cs:3
abstract string DomainName
Gets the domain in which the local computer is registered.
string Scheme
Gets the scheme name for this URI.
Definition: Uri.cs:702
The exception that is thrown when the value of an argument is outside the allowable range of values a...
static bool TryCreate(string uriString, UriKind uriKind, out Uri result)
Creates a new T:System.Uri using the specified T:System.String instance and a T:System....
Definition: Uri.cs:4782
A type representing a date and time value.
Provides information about the network connectivity of the local computer.
void Add(T item)
Adds an object to the end of the T:System.Collections.Generic.List`1.
Definition: List.cs:510
StringBuilder Append(char value, int repeatCount)
Appends a specified number of copies of the string representation of a Unicode character to this inst...
Represents a collection of key/value pairs that are organized based on the hash code of the key....
Definition: Hashtable.cs:17
virtual object SyncRoot
Gets an object that can be used to synchronize access to the T:System.Collections....
Definition: Hashtable.cs:645
Represents a mutable string of characters. This class cannot be inherited.To browse the ....
The exception that is thrown when one of the arguments provided to a method is not valid.
virtual void Remove(object key)
Removes the element with the specified key from the T:System.Collections.Hashtable.
Definition: Hashtable.cs:1349
Specifies that the class can be serialized.
static readonly string SchemeDelimiter
Specifies the characters that separate the communication protocol scheme from the address portion of ...
Definition: Uri.cs:179
The exception that is thrown when a call is made to the M:System.Threading.Thread....
Provides an object representation of a uniform resource identifier (URI) and easy access to the parts...
Definition: Uri.cs:19
static readonly string UriSchemeHttps
Specifies that the URI is accessed through the Secure Hypertext Transfer Protocol (HTTPS)....
Definition: Uri.cs:157
Defines a dictionary key/value pair that can be set or retrieved.
string Host
Gets the host component of this instance.
Definition: Uri.cs:587
static NumberFormatInfo InvariantInfo
Gets a read-only T:System.Globalization.NumberFormatInfo object that is culture-independent (invarian...
Provides culture-specific information for formatting and parsing numeric values.