Added some XML documentation comments
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ChunkStream.cs
|
||||
// Copied from System.Net.ChunkStream
|
||||
// Copied from System.Net.ChunkStream.cs
|
||||
//
|
||||
// Authors:
|
||||
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
|
||||
@@ -28,7 +28,7 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
@@ -39,6 +39,7 @@ namespace WebSocketSharp.Net {
|
||||
class ChunkStream {
|
||||
|
||||
enum State {
|
||||
|
||||
None,
|
||||
Body,
|
||||
BodyFinished,
|
||||
@@ -46,8 +47,9 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
|
||||
class Chunk {
|
||||
|
||||
public byte [] Bytes;
|
||||
public int Offset;
|
||||
public int Offset;
|
||||
|
||||
public Chunk (byte [] chunk)
|
||||
{
|
||||
@@ -63,19 +65,29 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
}
|
||||
|
||||
internal WebHeaderCollection headers;
|
||||
int chunkSize;
|
||||
int chunkRead;
|
||||
State state;
|
||||
//byte [] waitBuffer;
|
||||
#region Private Fields
|
||||
|
||||
int chunkRead;
|
||||
List<Chunk> chunks;
|
||||
int chunkSize;
|
||||
bool gotit;
|
||||
StringBuilder saved;
|
||||
bool sawCR;
|
||||
bool gotit;
|
||||
int trailerState;
|
||||
ArrayList chunks;
|
||||
|
||||
bool sawCR;
|
||||
State state;
|
||||
int trailerState;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Fields
|
||||
|
||||
internal WebHeaderCollection headers;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ChunkStream (byte [] buffer, int offset, int size, WebHeaderCollection headers)
|
||||
: this (headers)
|
||||
: this (headers)
|
||||
{
|
||||
Write (buffer, offset, size);
|
||||
}
|
||||
@@ -84,122 +96,26 @@ namespace WebSocketSharp.Net {
|
||||
{
|
||||
this.headers = headers;
|
||||
saved = new StringBuilder ();
|
||||
chunks = new ArrayList ();
|
||||
chunks = new List<Chunk> ();
|
||||
chunkSize = -1;
|
||||
}
|
||||
|
||||
public void ResetBuffer ()
|
||||
{
|
||||
chunkSize = -1;
|
||||
chunkRead = 0;
|
||||
chunks.Clear ();
|
||||
}
|
||||
|
||||
public void WriteAndReadBack (byte [] buffer, int offset, int size, ref int read)
|
||||
{
|
||||
if (offset + read > 0)
|
||||
Write (buffer, offset, offset+read);
|
||||
read = Read (buffer, offset, size);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public int Read (byte [] buffer, int offset, int size)
|
||||
{
|
||||
return ReadFromChunks (buffer, offset, size);
|
||||
}
|
||||
#region Properties
|
||||
|
||||
int ReadFromChunks (byte [] buffer, int offset, int size)
|
||||
{
|
||||
int count = chunks.Count;
|
||||
int nread = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
Chunk chunk = (Chunk) chunks [i];
|
||||
if (chunk == null)
|
||||
continue;
|
||||
|
||||
if (chunk.Offset == chunk.Bytes.Length) {
|
||||
chunks [i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
nread += chunk.Read (buffer, offset + nread, size - nread);
|
||||
if (nread == size)
|
||||
break;
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
public void Write (byte [] buffer, int offset, int size)
|
||||
{
|
||||
InternalWrite (buffer, ref offset, size);
|
||||
}
|
||||
|
||||
void InternalWrite (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
if (state == State.None) {
|
||||
state = GetChunkSize (buffer, ref offset, size);
|
||||
if (state == State.None)
|
||||
return;
|
||||
|
||||
saved.Length = 0;
|
||||
sawCR = false;
|
||||
gotit = false;
|
||||
}
|
||||
|
||||
if (state == State.Body && offset < size) {
|
||||
state = ReadBody (buffer, ref offset, size);
|
||||
if (state == State.Body)
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == State.BodyFinished && offset < size) {
|
||||
state = ReadCRLF (buffer, ref offset, size);
|
||||
if (state == State.BodyFinished)
|
||||
return;
|
||||
|
||||
sawCR = false;
|
||||
}
|
||||
|
||||
if (state == State.Trailer && offset < size) {
|
||||
state = ReadTrailer (buffer, ref offset, size);
|
||||
if (state == State.Trailer)
|
||||
return;
|
||||
|
||||
saved.Length = 0;
|
||||
sawCR = false;
|
||||
gotit = false;
|
||||
}
|
||||
|
||||
if (offset < size)
|
||||
InternalWrite (buffer, ref offset, size);
|
||||
public int ChunkLeft {
|
||||
get { return chunkSize - chunkRead; }
|
||||
}
|
||||
|
||||
public bool WantMore {
|
||||
get { return (chunkRead != chunkSize || chunkSize != 0 || state != State.None); }
|
||||
}
|
||||
|
||||
public int ChunkLeft {
|
||||
get { return chunkSize - chunkRead; }
|
||||
}
|
||||
|
||||
State ReadBody (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
if (chunkSize == 0)
|
||||
return State.BodyFinished;
|
||||
#endregion
|
||||
|
||||
int diff = size - offset;
|
||||
if (diff + chunkRead > chunkSize)
|
||||
diff = chunkSize - chunkRead;
|
||||
#region Private Methods
|
||||
|
||||
byte [] chunk = new byte [diff];
|
||||
Buffer.BlockCopy (buffer, offset, chunk, 0, diff);
|
||||
chunks.Add (new Chunk (chunk));
|
||||
offset += diff;
|
||||
chunkRead += diff;
|
||||
return (chunkRead == chunkSize) ? State.BodyFinished : State.Body;
|
||||
|
||||
}
|
||||
|
||||
State GetChunkSize (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
char c = '\0';
|
||||
@@ -207,7 +123,7 @@ namespace WebSocketSharp.Net {
|
||||
c = (char) buffer [offset++];
|
||||
if (c == '\r') {
|
||||
if (sawCR)
|
||||
ThrowProtocolViolation ("2 CR found");
|
||||
ThrowProtocolViolation ("2 CR found.");
|
||||
|
||||
sawCR = true;
|
||||
continue;
|
||||
@@ -223,12 +139,12 @@ namespace WebSocketSharp.Net {
|
||||
saved.Append (c);
|
||||
|
||||
if (saved.Length > 20)
|
||||
ThrowProtocolViolation ("chunk size too long.");
|
||||
ThrowProtocolViolation ("Chunk size too long.");
|
||||
}
|
||||
|
||||
if (!sawCR || c != '\n') {
|
||||
if (offset < size)
|
||||
ThrowProtocolViolation ("Missing \\n");
|
||||
ThrowProtocolViolation ("Missing \\n.");
|
||||
|
||||
try {
|
||||
if (saved.Length > 0) {
|
||||
@@ -256,31 +172,102 @@ namespace WebSocketSharp.Net {
|
||||
return State.Body;
|
||||
}
|
||||
|
||||
static string RemoveChunkExtension (string input)
|
||||
void InternalWrite (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
int idx = input.IndexOf (';');
|
||||
if (idx == -1)
|
||||
return input;
|
||||
return input.Substring (0, idx);
|
||||
if (state == State.None) {
|
||||
state = GetChunkSize (buffer, ref offset, size);
|
||||
if (state == State.None)
|
||||
return;
|
||||
|
||||
saved.Length = 0;
|
||||
sawCR = false;
|
||||
gotit = false;
|
||||
}
|
||||
|
||||
if (state == State.Body && offset < size) {
|
||||
state = ReadBody (buffer, ref offset, size);
|
||||
if (state == State.Body)
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == State.BodyFinished && offset < size) {
|
||||
state = ReadCRLF (buffer, ref offset, size);
|
||||
if (state == State.BodyFinished)
|
||||
return;
|
||||
|
||||
sawCR = false;
|
||||
}
|
||||
|
||||
if (state == State.Trailer && offset < size) {
|
||||
state = ReadTrailer (buffer, ref offset, size);
|
||||
if (state == State.Trailer)
|
||||
return;
|
||||
|
||||
saved.Length = 0;
|
||||
sawCR = false;
|
||||
gotit = false;
|
||||
}
|
||||
|
||||
if (offset < size)
|
||||
InternalWrite (buffer, ref offset, size);
|
||||
}
|
||||
|
||||
State ReadBody (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
if (chunkSize == 0)
|
||||
return State.BodyFinished;
|
||||
|
||||
int diff = size - offset;
|
||||
if (diff + chunkRead > chunkSize)
|
||||
diff = chunkSize - chunkRead;
|
||||
|
||||
byte [] chunk = new byte [diff];
|
||||
Buffer.BlockCopy (buffer, offset, chunk, 0, diff);
|
||||
chunks.Add (new Chunk (chunk));
|
||||
offset += diff;
|
||||
chunkRead += diff;
|
||||
return (chunkRead == chunkSize) ? State.BodyFinished : State.Body;
|
||||
}
|
||||
|
||||
State ReadCRLF (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
if (!sawCR) {
|
||||
if ((char) buffer [offset++] != '\r')
|
||||
ThrowProtocolViolation ("Expecting \\r");
|
||||
ThrowProtocolViolation ("Expecting \\r.");
|
||||
|
||||
sawCR = true;
|
||||
if (offset == size)
|
||||
return State.BodyFinished;
|
||||
}
|
||||
|
||||
|
||||
if (sawCR && (char) buffer [offset++] != '\n')
|
||||
ThrowProtocolViolation ("Expecting \\n");
|
||||
ThrowProtocolViolation ("Expecting \\n.");
|
||||
|
||||
return State.None;
|
||||
}
|
||||
|
||||
int ReadFromChunks (byte [] buffer, int offset, int size)
|
||||
{
|
||||
int count = chunks.Count;
|
||||
int nread = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
var chunk = chunks [i];
|
||||
if (chunk == null)
|
||||
continue;
|
||||
|
||||
if (chunk.Offset == chunk.Bytes.Length) {
|
||||
chunks [i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
nread += chunk.Read (buffer, offset + nread, size - nread);
|
||||
if (nread == size)
|
||||
break;
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
State ReadTrailer (byte [] buffer, ref int offset, int size)
|
||||
{
|
||||
char c = '\0';
|
||||
@@ -292,9 +279,10 @@ namespace WebSocketSharp.Net {
|
||||
offset++;
|
||||
return State.None;
|
||||
}
|
||||
|
||||
offset--;
|
||||
}
|
||||
|
||||
|
||||
int st = trailerState;
|
||||
string stString = "\r\n\r";
|
||||
while (offset < size && st < 4) {
|
||||
@@ -325,7 +313,7 @@ namespace WebSocketSharp.Net {
|
||||
return State.Trailer;
|
||||
}
|
||||
|
||||
StringReader reader = new StringReader (saved.ToString ());
|
||||
var reader = new StringReader (saved.ToString ());
|
||||
string line;
|
||||
while ((line = reader.ReadLine ()) != null && line != "")
|
||||
headers.Add (line);
|
||||
@@ -333,10 +321,50 @@ namespace WebSocketSharp.Net {
|
||||
return State.None;
|
||||
}
|
||||
|
||||
static string RemoveChunkExtension (string input)
|
||||
{
|
||||
int idx = input.IndexOf (';');
|
||||
if (idx == -1)
|
||||
return input;
|
||||
|
||||
return input.Substring (0, idx);
|
||||
}
|
||||
|
||||
static void ThrowProtocolViolation (string message)
|
||||
{
|
||||
WebException we = new WebException (message, null, WebExceptionStatus.ServerProtocolViolation, null);
|
||||
var we = new WebException (message, null, WebExceptionStatus.ServerProtocolViolation, null);
|
||||
throw we;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public int Read (byte [] buffer, int offset, int size)
|
||||
{
|
||||
return ReadFromChunks (buffer, offset, size);
|
||||
}
|
||||
|
||||
public void ResetBuffer ()
|
||||
{
|
||||
chunkSize = -1;
|
||||
chunkRead = 0;
|
||||
chunks.Clear ();
|
||||
}
|
||||
|
||||
public void Write (byte [] buffer, int offset, int size)
|
||||
{
|
||||
InternalWrite (buffer, ref offset, size);
|
||||
}
|
||||
|
||||
public void WriteAndReadBack (byte [] buffer, int offset, int size, ref int read)
|
||||
{
|
||||
if (offset + read > 0)
|
||||
Write (buffer, offset, offset + read);
|
||||
|
||||
read = Read (buffer, offset, size);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ChunkedInputStream.cs
|
||||
// Copied from System.Net.ChunkedInputStream
|
||||
// Copied from System.Net.ChunkedInputStream.cs
|
||||
//
|
||||
// Authors:
|
||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
||||
@@ -25,21 +25,15 @@
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WebSocketSharp.Net {
|
||||
|
||||
class ChunkedInputStream : RequestStream
|
||||
{
|
||||
HttpListenerContext context;
|
||||
ChunkStream decoder;
|
||||
bool disposed;
|
||||
bool no_more_data;
|
||||
class ChunkedInputStream : RequestStream {
|
||||
|
||||
class ReadBufferState {
|
||||
|
||||
@@ -60,6 +54,17 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
}
|
||||
|
||||
#region Fields
|
||||
|
||||
HttpListenerContext context;
|
||||
ChunkStream decoder;
|
||||
bool disposed;
|
||||
bool no_more_data;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public ChunkedInputStream (
|
||||
HttpListenerContext context, Stream stream, byte [] buffer, int offset, int length)
|
||||
: base (stream, buffer, offset, length)
|
||||
@@ -69,15 +74,23 @@ namespace WebSocketSharp.Net {
|
||||
decoder = new ChunkStream (coll);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Property
|
||||
|
||||
public ChunkStream Decoder {
|
||||
get { return decoder; }
|
||||
set { decoder = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Method
|
||||
|
||||
void OnRead (IAsyncResult base_ares)
|
||||
{
|
||||
ReadBufferState rb = (ReadBufferState) base_ares.AsyncState;
|
||||
HttpStreamAsyncResult ares = rb.Ares;
|
||||
var rb = (ReadBufferState) base_ares.AsyncState;
|
||||
var ares = rb.Ares;
|
||||
try {
|
||||
int nread = base.EndRead (base_ares);
|
||||
decoder.Write (ares.Buffer, ares.Offset, nread);
|
||||
@@ -90,6 +103,7 @@ namespace WebSocketSharp.Net {
|
||||
ares.Complete ();
|
||||
return;
|
||||
}
|
||||
|
||||
ares.Offset = 0;
|
||||
ares.Count = Math.Min (8192, decoder.ChunkLeft + 6);
|
||||
base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
|
||||
@@ -99,6 +113,10 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override IAsyncResult BeginRead (
|
||||
byte [] buffer, int offset, int count, AsyncCallback cback, object state)
|
||||
{
|
||||
@@ -110,18 +128,19 @@ namespace WebSocketSharp.Net {
|
||||
|
||||
int len = buffer.Length;
|
||||
if (offset < 0 || offset > len)
|
||||
throw new ArgumentOutOfRangeException ("offset exceeds the size of buffer");
|
||||
throw new ArgumentOutOfRangeException ("'offset' exceeds the size of buffer.");
|
||||
|
||||
if (count < 0 || offset > len - count)
|
||||
throw new ArgumentOutOfRangeException ("offset+size exceeds the size of buffer");
|
||||
throw new ArgumentOutOfRangeException ("'offset' + 'count' exceeds the size of buffer.");
|
||||
|
||||
HttpStreamAsyncResult ares = new HttpStreamAsyncResult ();
|
||||
var ares = new HttpStreamAsyncResult ();
|
||||
ares.Callback = cback;
|
||||
ares.State = state;
|
||||
if (no_more_data) {
|
||||
ares.Complete ();
|
||||
return ares;
|
||||
}
|
||||
|
||||
int nread = decoder.Read (buffer, offset, count);
|
||||
offset += nread;
|
||||
count -= nread;
|
||||
@@ -131,16 +150,18 @@ namespace WebSocketSharp.Net {
|
||||
ares.Complete ();
|
||||
return ares;
|
||||
}
|
||||
|
||||
if (!decoder.WantMore) {
|
||||
no_more_data = nread == 0;
|
||||
ares.Count = nread;
|
||||
ares.Complete ();
|
||||
return ares;
|
||||
}
|
||||
|
||||
ares.Buffer = new byte [8192];
|
||||
ares.Offset = 0;
|
||||
ares.Count = 8192;
|
||||
ReadBufferState rb = new ReadBufferState (buffer, offset, count, ares);
|
||||
var rb = new ReadBufferState (buffer, offset, count, ares);
|
||||
rb.InitialCount += nread;
|
||||
base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
|
||||
return ares;
|
||||
@@ -159,23 +180,25 @@ namespace WebSocketSharp.Net {
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (GetType ().ToString ());
|
||||
|
||||
HttpStreamAsyncResult my_ares = ares as HttpStreamAsyncResult;
|
||||
if (ares == null)
|
||||
throw new ArgumentException ("Invalid IAsyncResult", "ares");
|
||||
throw new ArgumentException ("Invalid IAsyncResult.", "ares");
|
||||
|
||||
if (!ares.IsCompleted)
|
||||
ares.AsyncWaitHandle.WaitOne ();
|
||||
|
||||
if (my_ares.Error != null)
|
||||
var ares_ = ares as HttpStreamAsyncResult;
|
||||
if (ares_.Error != null)
|
||||
throw new HttpListenerException (400, "I/O operation aborted.");
|
||||
|
||||
return my_ares.Count;
|
||||
return ares_.Count;
|
||||
}
|
||||
|
||||
public override int Read ([In,Out] byte [] buffer, int offset, int count)
|
||||
{
|
||||
IAsyncResult ares = BeginRead (buffer, offset, count, null, null);
|
||||
var ares = BeginRead (buffer, offset, count, null, null);
|
||||
return EndRead (ares);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
//
|
||||
// HttpListenerPrefixCollection.cs
|
||||
// Copied from System.Net.HttpListenerPrefixCollection
|
||||
// Copied from System.Net.HttpListenerPrefixCollection.cs
|
||||
//
|
||||
// Author:
|
||||
// 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
|
||||
@@ -31,38 +31,104 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace WebSocketSharp.Net {
|
||||
|
||||
/// <summary>
|
||||
/// Provides the collection used to store the URI prefixes for the <see cref="HttpListener"/>.
|
||||
/// </summary>
|
||||
public class HttpListenerPrefixCollection : ICollection<string>, IEnumerable<string>, IEnumerable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
HttpListener listener;
|
||||
List<string> prefixes;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Constructor
|
||||
|
||||
private HttpListenerPrefixCollection ()
|
||||
{
|
||||
prefixes = new List<string> ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Constructor
|
||||
|
||||
internal HttpListenerPrefixCollection (HttpListener listener)
|
||||
: this ()
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of prefixes contained in the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int"/> that contains the number of prefixes.
|
||||
/// </value>
|
||||
public int Count {
|
||||
get { return prefixes.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether access to the <see cref="HttpListenerPrefixCollection"/> is read-only.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always returns <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsReadOnly {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether access to the <see cref="HttpListenerPrefixCollection"/> is synchronized.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always returns <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsSynchronized {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Explicit Interface Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Gets an object that can be used to iterate through the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An object that implements the <see cref="IEnumerator"/> interface and provides access to
|
||||
/// the URI prefix strings in the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </returns>
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return prefixes.GetEnumerator ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <paramref name="uriPrefix"/> to the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that contains a URI prefix to add.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this <see cref="HttpListenerPrefixCollection"/> is closed.
|
||||
/// </exception>
|
||||
public void Add (string uriPrefix)
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
@@ -75,6 +141,12 @@ namespace WebSocketSharp.Net {
|
||||
EndPointManager.AddPrefix (uriPrefix, listener);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all URI prefixes from the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this <see cref="HttpListenerPrefixCollection"/> is closed.
|
||||
/// </exception>
|
||||
public void Clear ()
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
@@ -83,34 +155,96 @@ namespace WebSocketSharp.Net {
|
||||
EndPointManager.RemoveListener (listener);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the <see cref="HttpListenerPrefixCollection"/> contains
|
||||
/// the specified <paramref name="uriPrefix"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the <see cref="HttpListenerPrefixCollection"/> contains the specified <paramref name="uriPrefix"/>;
|
||||
/// otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that contains a URI prefix to test.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this <see cref="HttpListenerPrefixCollection"/> is closed.
|
||||
/// </exception>
|
||||
public bool Contains (string uriPrefix)
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
if (uriPrefix == null)
|
||||
throw new ArgumentNullException ("uriPrefix");
|
||||
|
||||
return prefixes.Contains (uriPrefix);
|
||||
}
|
||||
|
||||
public void CopyTo (string [] array, int offset)
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
prefixes.CopyTo (array, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the <see cref="HttpListenerPrefixCollection"/> to the specified <see cref="Array"/>.
|
||||
/// </summary>
|
||||
/// <param name="array">
|
||||
/// An <see cref="Array"/> that receives the URI prefix strings in the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// An <see cref="int"/> that contains the zero-based index in <paramref name="array"/> at which copying begins.
|
||||
/// </param>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this <see cref="HttpListenerPrefixCollection"/> is closed.
|
||||
/// </exception>
|
||||
public void CopyTo (Array array, int offset)
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
((ICollection) prefixes).CopyTo (array, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the <see cref="HttpListenerPrefixCollection"/> to the specified array of <see cref="string"/>.
|
||||
/// </summary>
|
||||
/// <param name="array">
|
||||
/// An array of <see cref="string"/> that receives the URI prefix strings in the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// An <see cref="int"/> that contains the zero-based index in <paramref name="array"/> at which copying begins.
|
||||
/// </param>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this <see cref="HttpListenerPrefixCollection"/> is closed.
|
||||
/// </exception>
|
||||
public void CopyTo (string [] array, int offset)
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
prefixes.CopyTo (array, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an object that can be used to iterate through the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An object that implements the IEnumerator<string> interface and provides access to
|
||||
/// the URI prefix strings in the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </returns>
|
||||
public IEnumerator<string> GetEnumerator ()
|
||||
{
|
||||
return prefixes.GetEnumerator ();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return prefixes.GetEnumerator ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified <paramref name="uriPrefix"/> from the list of prefixes in the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the <paramref name="uriPrefix"/> was found in the <see cref="HttpListenerPrefixCollection"/>
|
||||
/// and removed; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that contains a URI prefix to remove.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this <see cref="HttpListenerPrefixCollection"/> is closed.
|
||||
/// </exception>
|
||||
public bool Remove (string uriPrefix)
|
||||
{
|
||||
listener.CheckDisposed ();
|
||||
@@ -123,5 +257,7 @@ namespace WebSocketSharp.Net {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// HttpStreamAsyncResult.cs
|
||||
// Copied from System.Net.HttpStreamAsyncResult
|
||||
// Copied from System.Net.HttpStreamAsyncResult.cs
|
||||
//
|
||||
// Authors:
|
||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
||||
@@ -28,24 +28,33 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
namespace WebSocketSharp.Net {
|
||||
|
||||
class HttpStreamAsyncResult : IAsyncResult
|
||||
{
|
||||
class HttpStreamAsyncResult : IAsyncResult {
|
||||
|
||||
#region Private Fields
|
||||
|
||||
bool completed;
|
||||
ManualResetEvent handle;
|
||||
object locker = new object ();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Fields
|
||||
|
||||
internal AsyncCallback Callback;
|
||||
internal int Count;
|
||||
internal byte [] Buffer;
|
||||
internal Exception Error;
|
||||
internal int Offset;
|
||||
internal object State;
|
||||
internal int SynchRead;
|
||||
internal int SyncRead;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public object AsyncState {
|
||||
get { return State; }
|
||||
@@ -63,7 +72,7 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
|
||||
public bool CompletedSynchronously {
|
||||
get { return (SynchRead == Count); }
|
||||
get { return (SyncRead == Count); }
|
||||
}
|
||||
|
||||
public bool IsCompleted {
|
||||
@@ -74,6 +83,10 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Complete ()
|
||||
{
|
||||
lock (locker) {
|
||||
@@ -94,5 +107,7 @@ namespace WebSocketSharp.Net {
|
||||
Error = e;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ListenerPrefix.cs
|
||||
// Copied from System.ListenerPrefix
|
||||
// Copied from System.ListenerPrefix.cs
|
||||
//
|
||||
// Author:
|
||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
||||
@@ -35,21 +35,36 @@ namespace WebSocketSharp.Net {
|
||||
|
||||
sealed class ListenerPrefix {
|
||||
|
||||
IPAddress [] addresses;
|
||||
string host;
|
||||
string original;
|
||||
string path;
|
||||
ushort port;
|
||||
bool secure;
|
||||
#region Private Fields
|
||||
|
||||
IPAddress [] addresses;
|
||||
string host;
|
||||
string original;
|
||||
string path;
|
||||
ushort port;
|
||||
bool secure;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Field
|
||||
|
||||
public HttpListener Listener;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
// Must be called after calling ListenerPrefix.CheckUri.
|
||||
public ListenerPrefix (string prefix)
|
||||
{
|
||||
original = prefix;
|
||||
Parse (prefix);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public IPAddress [] Addresses {
|
||||
get { return addresses; }
|
||||
set { addresses = value; }
|
||||
@@ -71,19 +86,18 @@ namespace WebSocketSharp.Net {
|
||||
get { return secure; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Method
|
||||
|
||||
void Parse (string uri)
|
||||
{
|
||||
int default_port = (uri.StartsWith ("http://")) ? 80 : -1;
|
||||
if (default_port == -1) {
|
||||
default_port = (uri.StartsWith ("https://")) ? 443 : -1;
|
||||
int default_port = (uri.StartsWith ("http://")) ? 80 : 443;
|
||||
if (default_port == 443)
|
||||
secure = true;
|
||||
}
|
||||
|
||||
int length = uri.Length;
|
||||
int start_host = uri.IndexOf (':') + 3;
|
||||
if (start_host >= length)
|
||||
throw new ArgumentException ("No host specified.");
|
||||
|
||||
int colon = uri.IndexOf (':', start_host, length - start_host);
|
||||
int root;
|
||||
if (colon > 0) {
|
||||
@@ -95,15 +109,21 @@ namespace WebSocketSharp.Net {
|
||||
root = uri.IndexOf ('/', start_host, length - start_host);
|
||||
host = uri.Substring (start_host, root - start_host);
|
||||
path = uri.Substring (root);
|
||||
port = (ushort) default_port;
|
||||
}
|
||||
|
||||
if (path.Length != 1)
|
||||
path = path.Substring (0, path.Length - 1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public Methods
|
||||
|
||||
public static void CheckUri (string uri)
|
||||
{
|
||||
if (uri == null)
|
||||
throw new ArgumentNullException ("uriPrefix");
|
||||
throw new ArgumentNullException ("uri");
|
||||
|
||||
int default_port = (uri.StartsWith ("http://")) ? 80 : -1;
|
||||
if (default_port == -1)
|
||||
@@ -140,13 +160,13 @@ namespace WebSocketSharp.Net {
|
||||
}
|
||||
|
||||
if (uri [uri.Length - 1] != '/')
|
||||
throw new ArgumentException ("The prefix must end with '/'");
|
||||
throw new ArgumentException ("The prefix must end with '/'.");
|
||||
}
|
||||
|
||||
// Equals and GetHashCode are required to detect duplicates in HttpListenerPrefixCollection.
|
||||
public override bool Equals (object o)
|
||||
{
|
||||
ListenerPrefix other = o as ListenerPrefix;
|
||||
var other = o as ListenerPrefix;
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
@@ -162,5 +182,7 @@ namespace WebSocketSharp.Net {
|
||||
{
|
||||
return original;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// RequestStream.cs
|
||||
// Copied from System.Net.RequestStream
|
||||
// Copied from System.Net.RequestStream.cs
|
||||
//
|
||||
// Author:
|
||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
||||
@@ -29,27 +29,31 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WebSocketSharp.Net {
|
||||
|
||||
class RequestStream : Stream
|
||||
{
|
||||
byte [] buffer;
|
||||
int offset;
|
||||
int length;
|
||||
long remaining_body;
|
||||
bool disposed;
|
||||
System.IO.Stream stream;
|
||||
class RequestStream : Stream {
|
||||
|
||||
internal RequestStream (System.IO.Stream stream, byte [] buffer, int offset, int length)
|
||||
#region Fields
|
||||
|
||||
byte [] buffer;
|
||||
bool disposed;
|
||||
int length;
|
||||
int offset;
|
||||
long remaining_body;
|
||||
Stream stream;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
internal RequestStream (Stream stream, byte [] buffer, int offset, int length)
|
||||
: this (stream, buffer, offset, length, -1)
|
||||
{
|
||||
}
|
||||
|
||||
internal RequestStream (System.IO.Stream stream, byte [] buffer, int offset, int length, long contentlength)
|
||||
internal RequestStream (Stream stream, byte [] buffer, int offset, int length, long contentlength)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.buffer = buffer;
|
||||
@@ -58,6 +62,10 @@ namespace WebSocketSharp.Net {
|
||||
this.remaining_body = contentlength;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public override bool CanRead {
|
||||
get { return true; }
|
||||
}
|
||||
@@ -79,33 +87,30 @@ namespace WebSocketSharp.Net {
|
||||
set { throw new NotSupportedException (); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void Close ()
|
||||
{
|
||||
disposed = true;
|
||||
}
|
||||
#region Private Method
|
||||
|
||||
public override void Flush ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Returns 0 if we can keep reading from the base stream,
|
||||
// > 0 if we read something from the buffer.
|
||||
// -1 if we had a content length set and we finished reading that many bytes.
|
||||
int FillFromBuffer (byte [] buffer, int off, int count)
|
||||
int FillFromBuffer (byte [] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException ("buffer");
|
||||
if (off < 0)
|
||||
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
||||
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
||||
|
||||
int len = buffer.Length;
|
||||
if (off > len)
|
||||
throw new ArgumentException ("destination offset is beyond array size");
|
||||
if (off > len - count)
|
||||
throw new ArgumentException ("Reading would overrun buffer");
|
||||
if (offset > len)
|
||||
throw new ArgumentException ("Destination offset is beyond array size.");
|
||||
|
||||
if (offset > len - count)
|
||||
throw new ArgumentException ("Reading would overrun buffer.");
|
||||
|
||||
if (this.remaining_body == 0)
|
||||
return -1;
|
||||
@@ -120,21 +125,98 @@ namespace WebSocketSharp.Net {
|
||||
if (this.offset > this.buffer.Length - size) {
|
||||
size = Math.Min (size, this.buffer.Length - this.offset);
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
Buffer.BlockCopy (this.buffer, this.offset, buffer, off, size);
|
||||
Buffer.BlockCopy (this.buffer, this.offset, buffer, offset, size);
|
||||
this.offset += size;
|
||||
this.length -= size;
|
||||
if (this.remaining_body > 0)
|
||||
remaining_body -= size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override IAsyncResult BeginRead (
|
||||
byte [] buffer, int offset, int count, AsyncCallback cback, object state)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (GetType ().ToString ());
|
||||
|
||||
int nread = FillFromBuffer (buffer, offset, count);
|
||||
if (nread > 0 || nread == -1) {
|
||||
var ares = new HttpStreamAsyncResult ();
|
||||
ares.Buffer = buffer;
|
||||
ares.Offset = offset;
|
||||
ares.Count = count;
|
||||
ares.Callback = cback;
|
||||
ares.State = state;
|
||||
ares.SyncRead = nread;
|
||||
ares.Complete ();
|
||||
return ares;
|
||||
}
|
||||
|
||||
// Avoid reading past the end of the request to allow
|
||||
// for HTTP pipelining
|
||||
if (remaining_body >= 0 && count > remaining_body)
|
||||
count = (int) Math.Min (Int32.MaxValue, remaining_body);
|
||||
|
||||
return stream.BeginRead (buffer, offset, count, cback, state);
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginWrite (
|
||||
byte [] buffer, int offset, int count, AsyncCallback cback, object state)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override void Close ()
|
||||
{
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public override int EndRead (IAsyncResult ares)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (GetType ().ToString ());
|
||||
|
||||
if (ares == null)
|
||||
throw new ArgumentNullException ("ares");
|
||||
|
||||
if (ares is HttpStreamAsyncResult) {
|
||||
var ares_ = (HttpStreamAsyncResult) ares;
|
||||
if (!ares.IsCompleted)
|
||||
ares.AsyncWaitHandle.WaitOne ();
|
||||
|
||||
return ares_.SyncRead;
|
||||
}
|
||||
|
||||
// Close on exception?
|
||||
int nread = stream.EndRead (ares);
|
||||
if (remaining_body > 0 && nread > 0)
|
||||
remaining_body -= nread;
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
public override void EndWrite (IAsyncResult async_result)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override void Flush ()
|
||||
{
|
||||
}
|
||||
|
||||
public override int Read ([In,Out] byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (typeof (RequestStream).ToString ());
|
||||
throw new ObjectDisposedException (GetType () .ToString ());
|
||||
|
||||
// Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
|
||||
int nread = FillFromBuffer (buffer, offset, count);
|
||||
@@ -147,54 +229,7 @@ namespace WebSocketSharp.Net {
|
||||
nread = stream.Read (buffer, offset, count);
|
||||
if (nread > 0 && remaining_body > 0)
|
||||
remaining_body -= nread;
|
||||
return nread;
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
|
||||
AsyncCallback cback, object state)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (typeof (RequestStream).ToString ());
|
||||
|
||||
int nread = FillFromBuffer (buffer, offset, count);
|
||||
if (nread > 0 || nread == -1) {
|
||||
HttpStreamAsyncResult ares = new HttpStreamAsyncResult ();
|
||||
ares.Buffer = buffer;
|
||||
ares.Offset = offset;
|
||||
ares.Count = count;
|
||||
ares.Callback = cback;
|
||||
ares.State = state;
|
||||
ares.SynchRead = nread;
|
||||
ares.Complete ();
|
||||
return ares;
|
||||
}
|
||||
|
||||
// Avoid reading past the end of the request to allow
|
||||
// for HTTP pipelining
|
||||
if (remaining_body >= 0 && count > remaining_body)
|
||||
count = (int) Math.Min (Int32.MaxValue, remaining_body);
|
||||
return stream.BeginRead (buffer, offset, count, cback, state);
|
||||
}
|
||||
|
||||
public override int EndRead (IAsyncResult ares)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (typeof (RequestStream).ToString ());
|
||||
|
||||
if (ares == null)
|
||||
throw new ArgumentNullException ("async_result");
|
||||
|
||||
if (ares is HttpStreamAsyncResult) {
|
||||
HttpStreamAsyncResult r = (HttpStreamAsyncResult) ares;
|
||||
if (!ares.IsCompleted)
|
||||
ares.AsyncWaitHandle.WaitOne ();
|
||||
return r.SynchRead;
|
||||
}
|
||||
|
||||
// Close on exception?
|
||||
int nread = stream.EndRead (ares);
|
||||
if (remaining_body > 0 && nread > 0)
|
||||
remaining_body -= nread;
|
||||
return nread;
|
||||
}
|
||||
|
||||
@@ -213,15 +248,6 @@ namespace WebSocketSharp.Net {
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
|
||||
AsyncCallback cback, object state)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override void EndWrite (IAsyncResult async_result)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user