Added some XML documentation comments

This commit is contained in:
sta
2013-03-11 16:28:34 +09:00
parent 189a1fca3e
commit eeafa4ff8c
51 changed files with 3975 additions and 772 deletions

View File

@@ -8,7 +8,8 @@
// Daniel Nauck (dna@mono-project.de)
// Sebastien Pouliot (sebastien@ximian.com)
//
// Copyright (C) 2004,2009 Novell, Inc (http://www.novell.com)
// Copyright (c) 2004,2009 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -34,66 +35,200 @@ using System;
using System.Text;
using System.Globalization;
using System.Collections;
using System.Net;
namespace WebSocketSharp.Net {
// Supported cookie formats are:
// Netscape: http://home.netscape.com/newsref/std/cookie_spec.html
// RFC 2109: http://www.ietf.org/rfc/rfc2109.txt
// RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
/// <summary>
/// Provides a set of properties and methods to use to manage the HTTP Cookie.
/// </summary>
/// <remarks>
/// The Cookie class cannot be inherited.
/// </remarks>
[Serializable]
public sealed class Cookie
{
#region Fields
// Supported cookie formats are:
// Netscape: http://home.netscape.com/newsref/std/cookie_spec.html
// RFC 2109: http://www.ietf.org/rfc/rfc2109.txt
// RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
static char [] reservedCharsName = new char [] {' ', '=', ';', ',', '\n', '\r', '\t'};
static char [] portSeparators = new char [] {'"', ','};
static string tspecials = "()<>@,;:\\\"/[]?={} \t"; // from RFC 2965, 2068
#region Static Private Fields
string comment;
Uri commentUri;
bool discard;
string domain;
static char [] reservedCharsForName = new char [] {' ', '=', ';', ',', '\n', '\r', '\t'};
static char [] reservedCharsForValue = new char [] {';', ','};
#endregion
#region Private Fields
string comment;
Uri commentUri;
bool discard;
string domain;
DateTime expires;
bool httpOnly;
string name;
string path;
string port;
int [] ports;
bool secure;
bool httpOnly;
string name;
string path;
string port;
int [] ports;
bool secure;
DateTime timestamp;
string val;
int version;
string val;
int version;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Cookie"/> class.
/// </summary>
public Cookie ()
{
expires = DateTime.MinValue;
timestamp = DateTime.Now;
domain = String.Empty;
name = String.Empty;
val = String.Empty;
comment = String.Empty;
domain = String.Empty;
expires = DateTime.MinValue;
name = String.Empty;
path = String.Empty;
port = String.Empty;
ports = new int [] {};
timestamp = DateTime.Now;
val = String.Empty;
version = 0;
}
/// <summary>
/// Initializes a new instance of the <see cref="Cookie"/> class
/// with the specified <paramref name="name"/> and <paramref name="value"/>.
/// </summary>
/// <param name="name">
/// A <see cref="string"/> that contains the Name of the cookie.
/// </param>
/// <param name="value">
/// A <see cref="string"/> that contains the Value of the cookie.
/// </param>
/// <exception cref="CookieException">
/// <para>
/// <paramref name="name"/> is <see langword="null"/> or <see cref="String.Empty"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="name"/> contains an invalid character.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="value"/> is <see langword="null"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="value"/> contains a string not enclosed in double quotes
/// that contains an invalid character.
/// </para>
/// </exception>
public Cookie (string name, string value)
: this ()
{
Name = name;
Value = value;
string msg;
if (!CanSetName (name, out msg))
throw new CookieException (msg);
if (!CanSetValue (value, out msg))
throw new CookieException (msg);
this.name = name;
this.val = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="Cookie"/> class
/// with the specified <paramref name="name"/>, <paramref name="value"/> and <paramref name="path"/>.
/// </summary>
/// <param name="name">
/// A <see cref="string"/> that contains the Name of the cookie.
/// </param>
/// <param name="value">
/// A <see cref="string"/> that contains the Value of the cookie.
/// </param>
/// <param name="path">
/// A <see cref="string"/> that contains the value of the Path attribute of the cookie.
/// </param>
/// <exception cref="CookieException">
/// <para>
/// <paramref name="name"/> is <see langword="null"/> or <see cref="String.Empty"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="name"/> contains an invalid character.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="value"/> is <see langword="null"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="value"/> contains a string not enclosed in double quotes
/// that contains an invalid character.
/// </para>
/// </exception>
public Cookie (string name, string value, string path)
: this (name, value)
{
Path = path;
}
/// <summary>
/// Initializes a new instance of the <see cref="Cookie"/> class
/// with the specified <paramref name="name"/>, <paramref name="value"/>,
/// <paramref name="path"/> and <paramref name="domain"/>.
/// </summary>
/// <param name="name">
/// A <see cref="string"/> that contains the Name of the cookie.
/// </param>
/// <param name="value">
/// A <see cref="string"/> that contains the Value of the cookie.
/// </param>
/// <param name="path">
/// A <see cref="string"/> that contains the value of the Path attribute of the cookie.
/// </param>
/// <param name="domain">
/// A <see cref="string"/> that contains the value of the Domain attribute of the cookie.
/// </param>
/// <exception cref="CookieException">
/// <para>
/// <paramref name="name"/> is <see langword="null"/> or <see cref="String.Empty"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="name"/> contains an invalid character.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="value"/> is <see langword="null"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// <paramref name="value"/> contains a string not enclosed in double quotes
/// that contains an invalid character.
/// </para>
/// </exception>
public Cookie (string name, string value, string path, string domain)
: this (name, value, path)
{
@@ -114,34 +249,67 @@ namespace WebSocketSharp.Net {
#region Public Properties
/// <summary>
/// Gets or sets the value of the Comment attribute of the cookie.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains a comment to document intended use of the cookie.
/// </value>
public string Comment {
get { return comment; }
set { comment = value == null ? String.Empty : value; }
set { comment = value.IsNull () ? String.Empty : value; }
}
/// <summary>
/// Gets or sets the value of the CommentURL attribute of the cookie.
/// </summary>
/// <value>
/// A <see cref="Uri"/> that contains a URI that provides the comment
/// to document intended use of the cookie.
/// </value>
public Uri CommentUri {
get { return commentUri; }
set { commentUri = value; }
}
/// <summary>
/// Gets or sets a value indicating whether the client discards the cookie unconditionally
/// when the client terminates.
/// </summary>
/// <value>
/// <c>true</c> if the client discards the cookie unconditionally when the client terminates;
/// otherwise, <c>false</c>. The default is <c>false</c>.
/// </value>
public bool Discard {
get { return discard; }
set { discard = value; }
}
/// <summary>
/// Gets or sets the value of the Domain attribute of the cookie.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains a URI for which the cookie is valid.
/// </value>
public string Domain {
get { return domain; }
set {
if (String.IsNullOrEmpty (value)) {
if (value.IsNullOrEmpty ()) {
domain = String.Empty;
ExactDomain = true;
} else {
domain = value;
ExactDomain = (value [0] != '.');
ExactDomain = value [0] != '.';
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the cookie has expired.
/// </summary>
/// <value>
/// <c>true</c> if the cookie has expired; otherwise, <c>false</c>.
/// </value>
public bool Expired {
get {
return expires <= DateTime.Now &&
@@ -153,74 +321,129 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets or sets the value of the Expires attribute of the cookie.
/// </summary>
/// <value>
/// A <see cref="DateTime"/> that contains the date and time at which the cookie expires.
/// </value>
public DateTime Expires {
get { return expires; }
set { expires = value; }
}
/// <summary>
/// Gets or sets a value indicating non-HTTP APIs can access the cookie.
/// </summary>
/// <value>
/// <c>true</c> if non-HTTP APIs can not access the cookie; otherwise, <c>false</c>.
/// </value>
public bool HttpOnly {
get { return httpOnly; }
set { httpOnly = value; }
}
/// <summary>
/// Gets or sets the Name of the cookie.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains the Name of the cookie.
/// </value>
/// <exception cref="CookieException">
/// <para>
/// The value specified for a set operation is <see langword="null"/> or <see cref="String.Empty"/>.
/// </para>
/// <para>
/// - or -
/// </para>
/// <para>
/// The value specified for a set operation contains an invalid character.
/// </para>
/// </exception>
public string Name {
get { return name; }
set {
if (String.IsNullOrEmpty (value))
throw new CookieException ("Name cannot be empty");
if (value [0] == '$' || value.IndexOfAny (reservedCharsName) != -1) {
// see CookieTest, according to MS implementation
// the name value changes even though it's incorrect
name = String.Empty;
throw new CookieException ("Name contains invalid characters");
}
set {
string msg;
if (!CanSetName (value, out msg))
throw new CookieException (msg);
name = value;
name = value;
}
}
/// <summary>
/// Gets or sets the value of the Path attribute of the cookie.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains a subset of URI on the origin server
/// to which the cookie applies.
/// </value>
public string Path {
get { return (path == null) ? String.Empty : path; }
set { path = (value == null) ? String.Empty : value; }
get { return path; }
set { path = value.IsNull () ? String.Empty : value; }
}
/// <summary>
/// Gets or sets the value of the Port attribute of the cookie.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains a list of the TCP ports to which the cookie applies.
/// </value>
/// <exception cref="CookieException">
/// The value specified for a set operation could not be parsed or is not enclosed in double quotes.
/// </exception>
public string Port {
get { return port; }
set {
if (String.IsNullOrEmpty (value)) {
if (value.IsNullOrEmpty ()) {
port = String.Empty;
ports = new int [] {};
return;
}
if (value [0] != '"' || value [value.Length - 1] != '"') {
throw new CookieException("The 'Port'='" + value + "' part of the cookie is invalid. Port must be enclosed by double quotes.");
}
port = value;
string [] values = port.Split (portSeparators);
ports = new int[values.Length];
for (int i = 0; i < ports.Length; i++) {
ports [i] = Int32.MinValue;
if (values [i].Length == 0)
continue;
try {
ports [i] = Int32.Parse (values [i]);
} catch (Exception e) {
throw new CookieException("The 'Port'='" + value + "' part of the cookie is invalid. Invalid value: " + values [i], e);
}
}
Version = 1;
if (!value.IsEnclosedIn ('"'))
throw new CookieException ("The 'Port'='" + value + "' attribute of the cookie is invalid. Port must be enclosed in double quotes.");
string error;
if (!TryCreatePorts (value, out ports, out error))
throw new CookieException ("The 'Port'='" + value + "' attribute of the cookie is invalid. Invalid value: " + error);
port = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether the security level of the cookie is secure.
/// </summary>
/// <remarks>
/// When this property is <c>true</c>, the cookie may be included in the HTTP request
/// only if the request is transmitted over the HTTPS.
/// </remarks>
/// <value>
/// <c>true</c> if the security level of the cookie is secure; otherwise, <c>false</c>.
/// The default is <c>false</c>.
/// </value>
public bool Secure {
get { return secure; }
set { secure = value; }
}
/// <summary>
/// Gets the time when the cookie was issued.
/// </summary>
/// <value>
/// A <see cref="DateTime"/> that contains the time when the cookie was issued.
/// </value>
public DateTime TimeStamp {
get { return timestamp; }
}
/// <summary>
/// Gets or sets the Value of the cookie.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains the Value of the cookie.
/// </value>
public string Value {
get { return val; }
set {
@@ -233,7 +456,7 @@ namespace WebSocketSharp.Net {
// the semicolon and comma characters, yet it does. For now we'll follow
// the behaviour of MS.Net instead of the specs.
/*
if (value.IndexOfAny(reservedCharsValue) != -1)
if (value.IndexOfAny(reservedCharsForValue) != -1)
throw new CookieException("Invalid value. Value cannot contain semicolon or comma characters.");
*/
@@ -241,12 +464,22 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets or sets the value of the Version attribute of the cookie.
/// </summary>
/// <value>
/// An <see cref="int"/> that contains the version of the HTTP state management
/// to which the cookie conforms.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">
/// The value specified for a set operation is less than zero.
/// </exception>
public int Version {
get { return version; }
set {
if ((value < 0) || (value > 10))
version = 0;
else
if (value < 0)
throw new ArgumentOutOfRangeException();
else
version = value;
}
}
@@ -255,85 +488,130 @@ namespace WebSocketSharp.Net {
#region Private Methods
private static int hash (int i, int j, int k, int l, int m)
static bool CanSetName (string name, out string message)
{
if (name.IsNullOrEmpty ()) {
message = "Name can not be null or empty.";
return false;
}
if (name [0] == '$' || name.Contains (reservedCharsForName)) {
message = "Name contains an invalid character.";
return false;
}
message = String.Empty;
return true;
}
static bool CanSetValue (string value, out string message)
{
if (value.IsNull ()) {
message = "Value can not be null.";
return false;
}
if (value.Contains (reservedCharsForValue)) {
if (!value.IsEnclosedIn ('"')) {
message = "Value contains an invalid character.";
return false;
}
}
message = String.Empty;
return true;
}
static int Hash (int i, int j, int k, int l, int m)
{
return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25) ^ (m << 20 | m >> 12);
}
bool IsToken (string value)
{
int len = value.Length;
for (int i = 0; i < len; i++) {
char c = value [i];
if (c < 0x20 || c >= 0x7f || tspecials.IndexOf (c) != -1)
return false;
}
return true;
}
// See par 3.6 of RFC 2616
string QuotedString (string value)
string Quote (string value)
{
if (version == 0 || IsToken (value))
if (version == 0 || value.IsToken ())
return value;
else
return "\"" + value.Replace("\"", "\\\"") + "\"";
}
static bool TryCreatePorts (string value, out int [] result, out string parseError)
{
var values = value.Trim ('"').Split (',');
var tmp = new int [values.Length];
for (int i = 0; i < values.Length; i++) {
tmp [i] = int.MinValue;
var v = values [i].Trim ();
if (v.IsEmpty ())
continue;
if (!int.TryParse (v, out tmp [i])) {
result = new int [] {};
parseError = v;
return false;
}
}
result = tmp;
parseError = String.Empty;
return true;
}
#endregion
#region Internal Methods
// From server to client
internal string ToClientString ()
{
if (name.Length == 0)
if (name.IsEmpty ())
return String.Empty;
StringBuilder result = new StringBuilder (64);
var result = new StringBuilder (64);
if (version > 0)
result.Append ("Version=").Append (version).Append (";");
result.Append ("Version=").Append (version).Append ("; ");
result.Append (name).Append ("=").Append (val);
result.Append (name).Append ("=").Append (Quote (val));
if (!path.IsNullOrEmpty ())
result.Append ("; Path=").Append (path);
if (path != null && path.Length != 0)
result.Append (";Path=").Append (QuotedString (path));
if (!domain.IsNullOrEmpty ())
result.Append ("; Domain=").Append (domain);
if (domain != null && domain.Length != 0)
result.Append (";Domain=").Append (QuotedString (domain));
if (port != null && port.Length != 0)
result.Append (";Port=").Append (port);
if (!port.IsNullOrEmpty ())
result.Append ("; Port=").Append (port);
return result.ToString ();
}
// From client to server
internal string ToString (Uri uri)
{
if (name.Length == 0)
if (name.IsEmpty ())
return String.Empty;
StringBuilder result = new StringBuilder (64);
var result = new StringBuilder (64);
if (version > 0)
result.Append ("$Version=").Append (version).Append ("; ");
result.Append ("$Version=").Append (version).Append ("; ");
result.Append (name).Append ("=").Append (val);
if (version == 0)
return result.ToString ();
if (!String.IsNullOrEmpty (path))
if (!path.IsNullOrEmpty ())
result.Append ("; $Path=").Append (path);
else if (uri != null)
result.Append ("; $Path=/").Append (path);
else if (!uri.IsNull ())
result.Append ("; $Path=").Append (uri.GetAbsolutePath ());
else
result.Append ("; $Path=/");
bool append_domain = (uri == null) || (uri.Host != domain);
if (append_domain && !String.IsNullOrEmpty (domain))
result.Append ("; $Domain=").Append (domain);
bool append_domain = uri.IsNull () || uri.Host != domain;
if (append_domain && !domain.IsNullOrEmpty ())
result.Append ("; $Domain=").Append (domain);
if (port != null && port.Length != 0)
result.Append ("; $Port=").Append (port);
if (!port.IsNullOrEmpty ())
result.Append ("; $Port=").Append (port);
return result.ToString ();
}
@@ -342,34 +620,57 @@ namespace WebSocketSharp.Net {
#region Public Methods
public override bool Equals (Object obj)
/// <summary>
/// Determines whether the specified <see cref="Object"/> is equal to the current <see cref="Cookie"/>.
/// </summary>
/// <param name="comparand">
/// An <see cref="Object"/> to compare with the current <see cref="Cookie"/>.
/// </param>
/// <returns>
/// <c>true</c> if the specified <see cref="Object"/> is equal to the current <see cref="Cookie"/>;
/// otherwise, <c>false</c>.
/// </returns>
public override bool Equals (Object comparand)
{
Cookie c = obj as Cookie;
return c != null &&
String.Compare (this.name, c.Name, true, CultureInfo.InvariantCulture) == 0 &&
String.Compare (this.val, c.Value, false, CultureInfo.InvariantCulture) == 0 &&
String.Compare (this.Path, c.Path, false, CultureInfo.InvariantCulture) == 0 &&
String.Compare (this.domain, c.Domain, true, CultureInfo.InvariantCulture) == 0 &&
this.version == c.Version;
var cookie = comparand as Cookie;
return !cookie.IsNull() &&
String.Compare (this.name, cookie.Name, true, CultureInfo.InvariantCulture) == 0 &&
String.Compare (this.val, cookie.Value, false, CultureInfo.InvariantCulture) == 0 &&
String.Compare (this.path, cookie.Path, false, CultureInfo.InvariantCulture) == 0 &&
String.Compare (this.domain, cookie.Domain, true, CultureInfo.InvariantCulture) == 0 &&
this.version == cookie.Version;
}
/// <summary>
/// Serves as a hash function for a <see cref="Cookie"/> object.
/// </summary>
/// <returns>
/// An <see cref="int"/> that contains a hash code for this instance.
/// </returns>
public override int GetHashCode ()
{
return hash (
return Hash (
StringComparer.InvariantCultureIgnoreCase.GetHashCode (name),
val.GetHashCode (),
Path.GetHashCode (),
path.GetHashCode (),
StringComparer.InvariantCultureIgnoreCase.GetHashCode (domain),
version);
}
// returns a string that can be used to send a cookie to an Origin Server
// i.e., only used for clients
// see para 4.2.2 of RFC 2109 and para 3.3.4 of RFC 2965
// see also bug #316017
public override string ToString ()
/// <summary>
/// Returns a <see cref="string"/> that represents the current <see cref="Cookie"/>.
/// </summary>
/// <remarks>
/// This method returns a <see cref="string"/> to use to send an HTTP Cookie to an origin server.
/// </remarks>
/// <returns>
/// A <see cref="string"/> that represents the current <see cref="Cookie"/>.
/// </returns>
public override string ToString ()
{
// i.e., only used for clients
// see para 4.2.2 of RFC 2109 and para 3.3.4 of RFC 2965
// see also bug #316017
return ToString (null);
}

View File

@@ -7,7 +7,8 @@
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2004,2009 Novell, Inc (http://www.novell.com)
// Copyright (c) 2004,2009 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -33,11 +34,13 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Runtime.Serialization;
namespace WebSocketSharp.Net {
/// <summary>
/// Provides a collection container for instances of the <see cref="Cookie"/> class.
/// </summary>
[Serializable]
public class CookieCollection : ICollection, IEnumerable
{
@@ -48,7 +51,7 @@ namespace WebSocketSharp.Net {
{
if (x == null || y == null)
return 0;
int c1 = x.Name.Length + x.Value.Length;
int c2 = y.Name.Length + y.Value.Length;
@@ -56,10 +59,28 @@ namespace WebSocketSharp.Net {
}
}
#region Fields
#region Static Field
static CookieCollectionComparer Comparer = new CookieCollectionComparer ();
List<Cookie> list = new List<Cookie> ();
#endregion
#region Field
List<Cookie> list;
object sync;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="CookieCollection"/> class.
/// </summary>
public CookieCollection ()
{
list = new List<Cookie> ();
}
#endregion
@@ -73,7 +94,12 @@ namespace WebSocketSharp.Net {
#region Public Properties
// ICollection
/// <summary>
/// Gets the number of cookies contained in the <see cref="CookieCollection"/>.
/// </summary>
/// <value>
/// An <see cref="int"/> that indicates the number of cookies contained in the <see cref="CookieCollection"/>.
/// </value>
public int Count {
get { return list.Count; }
}
@@ -81,14 +107,42 @@ namespace WebSocketSharp.Net {
// LAMESPEC: So how is one supposed to create a writable CookieCollection
// instance?? We simply ignore this property, as this collection is always
// writable.
//
/// <summary>
/// Gets a value indicating whether the <see cref="CookieCollection"/> is read-only.
/// </summary>
/// <value>
/// <c>true</c> if the <see cref="CookieCollection"/> is read-only; otherwise, <c>false</c>.
/// The default is <c>true</c>.
/// </value>
public bool IsReadOnly {
get { return true; }
}
/// <summary>
/// Gets a value indicating whether access to the <see cref="CookieCollection"/> is thread safe.
/// </summary>
/// <value>
/// <c>true</c> if access to the <see cref="CookieCollection"/> is thread safe; otherwise, <c>false</c>.
/// The default is <c>false</c>.
/// </value>
public bool IsSynchronized {
get { return false; }
}
/// <summary>
/// Gets the <see cref="Cookie"/> with the specified <paramref name="index"/> from the <see cref="CookieCollection"/>.
/// </summary>
/// <value>
/// A <see cref="Cookie"/> with the specified <paramref name="index"/> in the <see cref="CookieCollection"/>.
/// </value>
/// <param name="index">
/// An <see cref="int"/> that is the zero-based index of the <see cref="Cookie"/> to find.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is less than zero or <paramref name="index"/> is greater than or
/// equal to <see cref="Count"/>.
/// </exception>
public Cookie this [int index] {
get {
if (index < 0 || index >= list.Count)
@@ -98,18 +152,45 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets the <see cref="Cookie"/> with the specified <paramref name="name"/> from the <see cref="CookieCollection"/>.
/// </summary>
/// <value>
/// A <see cref="Cookie"/> with the specified <paramref name="name"/> in the <see cref="CookieCollection"/>.
/// </value>
/// <param name="name">
/// A <see cref="string"/> that is the name of the <see cref="Cookie"/> to find.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="name"/> is <see langword="null"/>.
/// </exception>
public Cookie this [string name] {
get {
foreach (Cookie c in list) {
if (0 == String.Compare (c.Name, name, true, CultureInfo.InvariantCulture))
return c;
if (name.IsNull ())
throw new ArgumentNullException ("name");
foreach (var cookie in list) {
if (0 == String.Compare (cookie.Name, name, true, CultureInfo.InvariantCulture))
return cookie;
}
return null;
}
}
/// <summary>
/// Gets an object to use to synchronize access to the <see cref="CookieCollection"/>.
/// </summary>
/// <value>
/// An <see cref="Object"/> to use to synchronize access to the <see cref="CookieCollection"/>.
/// </value>
public Object SyncRoot {
get { return this; }
get {
if (sync.IsNull ())
sync = new object ();
return sync;
}
}
#endregion
@@ -124,16 +205,16 @@ namespace WebSocketSharp.Net {
for (int i = list.Count - 1; i >= 0; i--) {
Cookie c = list [i];
if (c.Version != cookie.Version)
if (0 != String.Compare (name, c.Name, true, CultureInfo.InvariantCulture))
continue;
if (0 != String.Compare (domain, c.Domain, true, CultureInfo.InvariantCulture))
continue;
if (0 != String.Compare (name, c.Name, true, CultureInfo.InvariantCulture))
if (0 != String.Compare (path, c.Path, false, CultureInfo.InvariantCulture))
continue;
if (0 != String.Compare (path, c.Path, true, CultureInfo.InvariantCulture))
if (c.Version != cookie.Version)
continue;
return i;
@@ -156,9 +237,18 @@ namespace WebSocketSharp.Net {
#region Public Methods
/// <summary>
/// Add the specified <see cref="Cookie"/> to the <see cref="CookieCollection"/>.
/// </summary>
/// <param name="cookie">
/// A <see cref="Cookie"/> to add to the <see cref="CookieCollection"/>.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>.
/// </exception>
public void Add (Cookie cookie)
{
if (cookie == null)
if (cookie.IsNull ())
throw new ArgumentNullException ("cookie");
int pos = SearchCookie (cookie);
@@ -168,25 +258,89 @@ namespace WebSocketSharp.Net {
list [pos] = cookie;
}
/// <summary>
/// Add the elements of the specified <see cref="CookieCollection"/> to the current <see cref="CookieCollection"/>.
/// </summary>
/// <param name="cookies">
/// A <see cref="CookieCollection"/> to add to the current <see cref="CookieCollection"/>.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookies"/> is <see langword="null"/>.
/// </exception>
public void Add (CookieCollection cookies)
{
if (cookies == null)
if (cookies.IsNull ())
throw new ArgumentNullException ("cookies");
foreach (Cookie c in cookies)
Add (c);
foreach (Cookie cookie in cookies)
Add (cookie);
}
/// <summary>
/// Copies the elements of the <see cref="CookieCollection"/> to the specified <see cref="Array"/>,
/// starting at the specified <paramref name="index"/> in the <paramref name="array"/>.
/// </summary>
/// <param name="array">
/// An <see cref="Array"/> that is the destination of the elements copied from the <see cref="CookieCollection"/>.
/// </param>
/// <param name="index">
/// An <see cref="int"/> that indicates the zero-based index in <paramref name="array"/> at which copying begins.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is less than zero.
/// </exception>
public void CopyTo (Array array, int index)
{
if (array.IsNull ())
throw new ArgumentNullException ("array");
if (index < 0)
throw new ArgumentOutOfRangeException ("index", "Must not be less than zero.");
// TODO: Support for ArgumentException and InvalidCastException.
(list as IList).CopyTo (array, index);
}
/// <summary>
/// Copies the elements of the <see cref="CookieCollection"/> to the specified array of <see cref="Cookie"/>,
/// starting at the specified <paramref name="index"/> in the <paramref name="array"/>.
/// </summary>
/// <param name="array">
/// An array of <see cref="Cookie"/> that is the destination of the elements copied from the <see cref="CookieCollection"/>.
/// </param>
/// <param name="index">
/// An <see cref="int"/> that indicates the zero-based index in <paramref name="array"/> at which copying begins.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is less than zero.
/// </exception>
public void CopyTo (Cookie [] array, int index)
{
if (array.IsNull ())
throw new ArgumentNullException ("array");
if (index < 0)
throw new ArgumentOutOfRangeException ("index", "Must not be less than zero.");
// TODO: Support for ArgumentException.
list.CopyTo (array, index);
}
/// <summary>
/// Gets the enumerator to use to iterate through the <see cref="CookieCollection"/>.
/// </summary>
/// <returns>
/// An instance of an implementation of the <see cref="IEnumerator"/> interface
/// to use to iterate through the <see cref="CookieCollection"/>.
/// </returns>
public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();

View File

@@ -1,10 +1,12 @@
//
// CookieException.cs
// Copied from System.Net.CookieException
// Copied from System.Net.CookieException.cs
//
// Author:
// Lawrence Pit (loz@cable.a2000.nl)
//
// Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
@@ -28,42 +30,97 @@
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace WebSocketSharp.Net {
/// <summary>
/// The exception that is thrown when a <see cref="Cookie"/> gets an error.
/// </summary>
[Serializable]
public class CookieException : FormatException, ISerializable
{
// Constructors
#region Internal Constructors
internal CookieException (string message)
: base (message)
{
}
internal CookieException (string message, Exception innerException)
: base (message, innerException)
{
}
#endregion
#region Protected Constructor
/// <summary>
/// Initializes a new instance of the <see cref="CookieException"/> class
/// with the specified <see cref="SerializationInfo"/> and <see cref="StreamingContext"/>.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that holds the serialized object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that contains the contextual information about the source or destination.
/// </param>
protected CookieException (SerializationInfo serializationInfo, StreamingContext streamingContext)
: base (serializationInfo, streamingContext)
{
}
#endregion
#region Public Constructor
/// <summary>
/// Initializes a new instance of the <see cref="CookieException"/> class.
/// </summary>
public CookieException ()
: base ()
{
}
internal CookieException (string msg)
: base (msg)
#endregion
#region Explicit Interface Implementation
/// <summary>
/// Populates the specified <see cref="SerializationInfo"/> with the data needed to serialize the <see cref="CookieException"/>.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that holds the serialized object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that specifies the destination for the serialization.
/// </param>
[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
base.GetObjectData (serializationInfo, streamingContext);
}
internal CookieException (string msg, Exception e)
: base (msg, e)
{
}
#endregion
protected CookieException (SerializationInfo info, StreamingContext context)
: base (info, context)
{
}
// Methods
void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
{
base.GetObjectData (info, context);
}
#region Public Method
/// <summary>
/// Populates the specified <see cref="SerializationInfo"/> with the data needed to serialize the <see cref="CookieException"/>.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that holds the serialized object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that specifies the destination for the serialization.
/// </param>
[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public override void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
base.GetObjectData (serializationInfo, streamingContext);
}
#endregion
}
}

View File

@@ -40,7 +40,7 @@ using System.Text;
namespace WebSocketSharp.Net {
/// <summary>
/// Provides access to the HTTP request objects sent to a <see cref="HttpListener"/> instance.
/// Provides access to a request to a <see cref="HttpListener"/> instance.
/// </summary>
/// <remarks>
/// The HttpListenerRequest class cannot be inherited.
@@ -84,8 +84,8 @@ namespace WebSocketSharp.Net {
internal HttpListenerRequest (HttpListenerContext context)
{
this.context = context;
headers = new WebHeaderCollection ();
version = HttpVersion.Version10;
headers = new WebHeaderCollection ();
version = HttpVersion.Version10;
}
#endregion
@@ -126,7 +126,7 @@ namespace WebSocketSharp.Net {
/// Gets the encoding that can be used with the entity body data included in the request.
/// </summary>
/// <value>
/// A <see cref="Encoding"/> that contains the encoding that can be used with entity body data.
/// A <see cref="Encoding"/> that contains the encoding that can be used with the entity body data.
/// </value>
public Encoding ContentEncoding {
// TODO: Always returns Encoding.Default
@@ -142,7 +142,7 @@ namespace WebSocketSharp.Net {
/// </summary>
/// <value>
/// A <see cref="long"/> that contains the value of the Content-Length entity-header field.
/// <c>-1</c> if the size is not known.
/// The value is a number of bytes in the entity body data. <c>-1</c> if the size is not known.
/// </value>
public long ContentLength64 {
get { return content_length; }

View File

@@ -6,7 +6,7 @@
// Gonzalo Paniagua Javier (gonzalo@novell.com)
//
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
// Copyright (c) 2012 sta.blockhead (sta.blockhead@gmail.com)
// Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -29,13 +29,21 @@
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace WebSocketSharp.Net {
/// <summary>
/// Provides access to a response to a request being processed by a <see cref="HttpListener"/> instance.
/// </summary>
/// <remarks>
/// The HttpListenerResponse class cannot be inherited.
/// </remarks>
public sealed class HttpListenerResponse : IDisposable
{
#region Private Fields
@@ -59,7 +67,7 @@ namespace WebSocketSharp.Net {
#endregion
#region Internal Fields
#region Internal Field
internal bool HeadersSent;
@@ -85,17 +93,29 @@ namespace WebSocketSharp.Net {
#region Public Properties
/// <summary>
/// Gets or sets the encoding that can be used with the entity body data included in the response.
/// </summary>
/// <value>
/// A <see cref="Encoding"/> that contains the encoding that can be used with the entity body data.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
public Encoding ContentEncoding {
get {
if (content_encoding == null)
content_encoding = Encoding.Default;
return content_encoding;
}
set {
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
// TODO: is null ok?
if (HeadersSent)
throw new InvalidOperationException ("Cannot be changed after headers are sent.");
@@ -103,6 +123,22 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets or sets the size of the entity body data included in the response.
/// </summary>
/// <value>
/// A <see cref="long"/> that contains the value of the Content-Length entity-header field.
/// The value is a number of bytes in the entity body data.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// The value specified for a set operation is less than zero.
/// </exception>
public long ContentLength64 {
get { return content_length; }
set {
@@ -113,51 +149,103 @@ namespace WebSocketSharp.Net {
throw new InvalidOperationException ("Cannot be changed after headers are sent.");
if (value < 0)
throw new ArgumentOutOfRangeException ("Must be >= 0", "value");
throw new ArgumentOutOfRangeException ("Must be greater than or equal zero.", "value");
cl_set = true;
content_length = value;
}
}
/// <summary>
/// Gets or sets the media type of the entity body included in the response.
/// </summary>
/// <value>
/// The type of the content.
/// A <see cref="string"/> that contains the value of the Content-Type entity-header field.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The value specified for a set operation is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// The value specified for a set operation is a <see cref="String.Empty"/>.
/// </exception>
public string ContentType {
get { return content_type; }
set {
// TODO: is null ok?
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
if (HeadersSent)
throw new InvalidOperationException ("Cannot be changed after headers are sent.");
if (value.IsNull ())
throw new ArgumentNullException ("value");
if (value.IsEmpty ())
throw new ArgumentException ("Must not be empty.", "value");
content_type = value;
}
}
// RFC 2109, 2965 + the netscape specification at http://wp.netscape.com/newsref/std/cookie_spec.html
/// <summary>
/// Gets or sets the cookies returned with the response.
/// </summary>
/// <value>
/// A <see cref="CookieCollection"/> that contains the cookies returned with the response.
/// </value>
public CookieCollection Cookies {
get {
if (cookies == null)
cookies = new CookieCollection ();
return cookies;
}
set { cookies = value; } // null allowed?
set { cookies = value; }
}
/// <summary>
/// Gets or sets the HTTP headers returned to the client.
/// </summary>
/// <value>
/// A <see cref="WebHeaderCollection"/> that contains the HTTP headers returned to the client.
/// </value>
public WebHeaderCollection Headers {
get { return headers; }
set {
/**
* "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, or
* WWW-Authenticate header using the Headers property, an exception will be
* thrown. Use the KeepAlive or ContentLength64 properties to set these headers.
* You cannot set the Transfer-Encoding or WWW-Authenticate headers manually."
*/
// TODO: check if this is marked readonly after headers are sent.
/*
* "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, or
* WWW-Authenticate header using the Headers property, an exception will be
* thrown. Use the KeepAlive or ContentLength64 properties to set these headers.
* You cannot set the Transfer-Encoding or WWW-Authenticate headers manually."
*/
// TODO: Support for InvalidOperationException.
// TODO: check if this is marked readonly after headers are sent.
headers = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether the server requests a persistent connection.
/// </summary>
/// <value>
/// <c>true</c> if the server requests a persistent connection; otherwise, <c>false</c>.
/// The default is <c>true</c>.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
public bool KeepAlive {
get { return keep_alive; }
set {
@@ -171,8 +259,20 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets a <see cref="Stream"/> to use to write the entity body data.
/// </summary>
/// <value>
/// A <see cref="Stream"/> to use to write the entity body data.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
public Stream OutputStream {
get {
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
if (output_stream == null)
output_stream = context.Connection.GetResponseStream ();
@@ -180,6 +280,25 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets or sets the HTTP version used in the response.
/// </summary>
/// <value>
/// A <see cref="Version"/> that contains the HTTP version used in the response.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The value specified for a set operation is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// The value specified for a set operation does not have its <see cref="Version.Major">Major</see> property set to 1 or
/// does not have its <see cref="Version.Minor">Minor</see> property set to either 0 or 1.
/// </exception>
public Version ProtocolVersion {
get { return version; }
set {
@@ -188,20 +307,32 @@ namespace WebSocketSharp.Net {
if (HeadersSent)
throw new InvalidOperationException ("Cannot be changed after headers are sent.");
if (value == null)
throw new ArgumentNullException ("value");
if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
throw new ArgumentException ("Must be 1.0 or 1.1", "value");
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
version = value;
}
}
/// <summary>
/// Gets or sets the URL to which the client is redirected to locate a requested resource.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains the value of the Location response-header field.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
/// <exception cref="ArgumentException">
/// The value specified for a set operation is a <see cref="String.Empty"/>.
/// </exception>
public string RedirectLocation {
get { return location; }
set {
@@ -211,10 +342,25 @@ namespace WebSocketSharp.Net {
if (HeadersSent)
throw new InvalidOperationException ("Cannot be changed after headers are sent.");
if (value.IsEmpty ())
throw new ArgumentException ("Must not be empty.", "value");
location = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether the response uses the chunked transfer encoding.
/// </summary>
/// <value>
/// <c>true</c> if the response uses the chunked transfer encoding; otherwise, <c>false</c>.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
public bool SendChunked {
get { return chunked; }
set {
@@ -228,6 +374,22 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets or sets the HTTP status code returned to the client.
/// </summary>
/// <value>
/// An <see cref="int"/> that indicates the HTTP status code for the response to the request.
/// The default is <see cref="HttpStatusCode.OK"/>.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
/// <exception cref="InvalidOperationException">
/// The response has been sent already.
/// </exception>
/// <exception cref="ProtocolViolationException">
/// The value specified for a set operation is invalid. Valid values are between 100 and 999.
/// </exception>
public int StatusCode {
get { return status_code; }
set {
@@ -245,10 +407,18 @@ namespace WebSocketSharp.Net {
}
}
/// <summary>
/// Gets or sets a description of the HTTP status code returned to the client.
/// </summary>
/// <value>
/// A <see cref="String"/> that contains a description of the HTTP status code returned to the client.
/// </value>
public string StatusDescription {
get { return status_description; }
set {
status_description = value;
status_description = value.IsNullOrEmpty ()
? status_code.GetStatusDescription ()
: value;
}
}
@@ -256,27 +426,39 @@ namespace WebSocketSharp.Net {
#region Private Methods
bool CanAddOrUpdate (Cookie cookie)
{
if (Cookies.Count == 0)
return true;
var found = FindCookie (cookie);
if (found.Count() == 0)
return true;
foreach (var c in found)
if (c.Version == cookie.Version)
return true;
return false;
}
void Close (bool force)
{
disposed = true;
context.Connection.Close (force);
}
bool FindCookie (Cookie cookie)
IEnumerable<Cookie> FindCookie (Cookie cookie)
{
string name = cookie.Name;
string domain = cookie.Domain;
string path = cookie.Path;
foreach (Cookie c in cookies) {
if (name != c.Name)
continue;
if (domain != c.Domain)
continue;
if (path == c.Path)
return true;
}
var name = cookie.Name;
var domain = cookie.Domain;
var path = cookie.Path;
return false;
return from Cookie c in Cookies
where String.Compare (name, c.Name, true, CultureInfo.InvariantCulture) == 0 &&
String.Compare (domain, c.Domain, true, CultureInfo.InvariantCulture) == 0 &&
String.Compare (path, c.Path, false, CultureInfo.InvariantCulture) == 0
select c;
}
void Init ()
@@ -308,7 +490,7 @@ namespace WebSocketSharp.Net {
}
if (headers ["Server"] == null)
headers.SetInternal ("Server", "Mono-HTTPAPI/1.0");
headers.SetInternal ("Server", "WebSocketSharp-HTTPAPI/1.0");
CultureInfo inv = CultureInfo.InvariantCulture;
if (headers ["Date"] == null)
@@ -394,6 +576,9 @@ namespace WebSocketSharp.Net {
#region Explicit Interface Implementation
/// <summary>
/// Releases all resource used by the <see cref="HttpListenerResponse"/>.
/// </summary>
void IDisposable.Dispose ()
{
Close (true); // TODO: Abort or Close?
@@ -403,6 +588,9 @@ namespace WebSocketSharp.Net {
#region Public Methods
/// <summary>
/// Closes the connection to the client without sending a response.
/// </summary>
public void Abort ()
{
if (disposed)
@@ -411,21 +599,44 @@ namespace WebSocketSharp.Net {
Close (true);
}
/// <summary>
/// Adds the specified HTTP header <paramref name="name"/> and <paramref name="value"/> to
/// the headers for this response.
/// </summary>
/// <param name="name">
/// A <see cref="string"/> that contains the name of the HTTP header to add.
/// </param>
/// <param name="value">
/// A <see cref="string"/> that contains the value of the HTTP header to add.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="name"/> is <see langword="null"/> or <see cref="String.Empty"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// The length of <paramref name="value"/> is greater than 65,535 characters.
/// </exception>
public void AddHeader (string name, string value)
{
if (name == null)
if (name.IsNullOrEmpty())
throw new ArgumentNullException ("name");
if (name == "")
throw new ArgumentException ("'name' cannot be empty", "name");
// TODO: Check for forbidden headers and invalid characters.
// TODO: check for forbidden headers and invalid characters
if (value.Length > 65535)
throw new ArgumentOutOfRangeException ("value");
headers.Set (name, value);
}
/// <summary>
/// Adds the specified <see cref="Cookie"/> to the <see cref="Cookies"/> sent with the response.
/// </summary>
/// <param name="cookie">
/// A <see cref="Cookie"/> to add to the <see cref="Cookies"/>.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>.
/// </exception>
public void AppendCookie (Cookie cookie)
{
if (cookie == null)
@@ -434,13 +645,26 @@ namespace WebSocketSharp.Net {
Cookies.Add (cookie);
}
/// <summary>
/// Appends a <paramref name="value"/> to the specified HTTP header sent with the response.
/// </summary>
/// <param name="name">
/// A <see cref="string"/> that contains the name of the HTTP header to append <paramref name="value"/> to.
/// </param>
/// <param name="value">
/// A <see cref="string"/> that contains the value to append to the HTTP header.
/// </param>
/// <exception cref="ArgumentException">
/// <paramref name="name"/> is <see langword="null"/> or <see cref="String.Empty"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// The length of <paramref name="value"/> is greater than 65,535 characters.
/// </exception>
public void AppendHeader (string name, string value)
{
if (name == null)
throw new ArgumentNullException ("name");
if (name == "")
throw new ArgumentException ("'name' cannot be empty", "name");
// TODO: Check for forbidden headers and invalid characters.
if (name.IsNullOrEmpty())
throw new ArgumentException ("'name' cannot be null or empty", "name");
if (value.Length > 65535)
throw new ArgumentOutOfRangeException ("value");
@@ -448,6 +672,10 @@ namespace WebSocketSharp.Net {
headers.Add (name, value);
}
/// <summary>
/// Sends the response to the client and releases the resources associated with
/// the <see cref="HttpListenerResponse"/> instance.
/// </summary>
public void Close ()
{
if (disposed)
@@ -456,20 +684,42 @@ namespace WebSocketSharp.Net {
Close (false);
}
/// <summary>
/// Sends the response with the specified array of <see cref="byte"/> to the client and
/// releases the resources associated with the <see cref="HttpListenerResponse"/> instance.
/// </summary>
/// <param name="responseEntity">
/// An array of <see cref="byte"/> that contains the response entity body data.
/// </param>
/// <param name="willBlock">
/// <c>true</c> if this method blocks execution while flushing the stream to the client; otherwise, <c>false</c>.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="responseEntity"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// This object is closed.
/// </exception>
public void Close (byte [] responseEntity, bool willBlock)
{
if (disposed)
return;
throw new ObjectDisposedException (GetType ().ToString ());
if (responseEntity == null)
throw new ArgumentNullException ("responseEntity");
// TODO: if willBlock -> BeginWrite + Close ?
// TODO: If willBlock -> BeginWrite + Close?
ContentLength64 = responseEntity.Length;
OutputStream.Write (responseEntity, 0, (int) content_length);
Close (false);
}
/// <summary>
/// Copies properties from the specified <see cref="HttpListenerResponse"/> to this response.
/// </summary>
/// <param name="templateResponse">
/// A <see cref="HttpListenerResponse"/> to copy.
/// </param>
public void CopyFrom (HttpListenerResponse templateResponse)
{
headers.Clear ();
@@ -481,25 +731,40 @@ namespace WebSocketSharp.Net {
version = templateResponse.version;
}
/// <summary>
/// Configures the response to redirect the client's request to the specified <paramref name="url"/>.
/// </summary>
/// <param name="url">
/// A <see cref="string"/> that contains a URL to redirect the client's request to.
/// </param>
public void Redirect (string url)
{
StatusCode = 302; // Found
StatusCode = (int) HttpStatusCode.Redirect;
location = url;
}
/// <summary>
/// Adds or updates a <see cref="Cookie"/> in the <see cref="Cookies"/> sent with the response.
/// </summary>
/// <param name="cookie">
/// A <see cref="Cookie"/> to set.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="cookie"/> already exists in the <see cref="Cookies"/> and
/// could not be replaced.
/// </exception>
public void SetCookie (Cookie cookie)
{
if (cookie == null)
if (cookie.IsNull())
throw new ArgumentNullException ("cookie");
if (cookies != null) {
if (FindCookie (cookie))
throw new ArgumentException ("The cookie already exists.");
} else {
cookies = new CookieCollection ();
}
if (!CanAddOrUpdate (cookie))
throw new ArgumentException ("Cannot be replaced.", "cookie");
cookies.Add (cookie);
Cookies.Add (cookie);
}
#endregion