Added some XML documentation comments
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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 ();
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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; }
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user