Fix for HTTP Basic/Digest Authentication
parent
0a263622f0
commit
537229902f
@ -1,69 +1,67 @@
|
|||||||
//
|
#region License
|
||||||
// AuthenticationSchemes.cs
|
/*
|
||||||
// Copied from System.Net.AuthenticationSchemes.cs
|
* AuthenticationSchemes.cs
|
||||||
//
|
*
|
||||||
// Author:
|
* This code is derived from System.Net.AuthenticationSchemes.cs of Mono
|
||||||
// Atsushi Enomoto <atsushi@ximian.com>
|
* (http://www.mono-project.com).
|
||||||
//
|
*
|
||||||
// Copyright (C) 2005 Novell, Inc. (http://www.novell.com)
|
* The MIT License
|
||||||
//
|
*
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||||||
// a copy of this software and associated documentation files (the
|
* Copyright (c) 2012-2013 sta.blockhead
|
||||||
// "Software"), to deal in the Software without restriction, including
|
*
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
* in the Software without restriction, including without limitation the rights
|
||||||
// the following conditions:
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
// The above copyright notice and this permission notice shall be
|
* furnished to do so, subject to the following conditions:
|
||||||
// included in all copies or substantial portions of the Software.
|
*
|
||||||
//
|
* The above copyright notice and this permission notice shall be included in
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* all copies or substantial portions of the Software.
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
*
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
using System;
|
#region Authors
|
||||||
|
/*
|
||||||
namespace WebSocketSharp.Net {
|
* Authors:
|
||||||
|
* Atsushi Enomoto <atsushi@ximian.com>
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
using System;
|
||||||
/// Contains the values of the schemes for authentication.
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum AuthenticationSchemes {
|
|
||||||
|
|
||||||
/// <summary>
|
namespace WebSocketSharp.Net
|
||||||
/// Indicates that no authentication is allowed.
|
{
|
||||||
/// </summary>
|
/// <summary>
|
||||||
None,
|
/// Contains the values of the schemes for authentication.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Indicates digest authentication.
|
[Flags]
|
||||||
/// </summary>
|
public enum AuthenticationSchemes
|
||||||
Digest = 1,
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates negotiating with the client to determine the authentication scheme.
|
/// Indicates that no authentication is allowed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Negotiate = 2,
|
None,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates NTLM authentication.
|
/// Indicates digest authentication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Ntlm = 4,
|
Digest = 1,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates Windows authentication.
|
/// Indicates basic authentication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IntegratedWindowsAuthentication = 6,
|
Basic = 8,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates basic authentication.
|
/// Indicates anonymous authentication.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Basic = 8,
|
Anonymous = 0x8000,
|
||||||
/// <summary>
|
}
|
||||||
/// Indicates anonymous authentication.
|
|
||||||
/// </summary>
|
|
||||||
Anonymous = 0x8000,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,81 @@
|
|||||||
|
#region License
|
||||||
|
/*
|
||||||
|
* HttpBasicIdentity.cs
|
||||||
|
*
|
||||||
|
* This code is derived from System.Net.HttpListenerBasicIdentity.cs of Mono
|
||||||
|
* (http://www.mono-project.com).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||||||
|
* Copyright (c) 2014 sta.blockhead
|
||||||
|
*
|
||||||
|
* 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 without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Authors
|
||||||
|
/*
|
||||||
|
* Authors:
|
||||||
|
* Gonzalo Paniagua Javier <gonzalo@novell.com>
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Security.Principal;
|
||||||
|
|
||||||
|
namespace WebSocketSharp.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the user name and password from an HTTP Basic authentication request.
|
||||||
|
/// </summary>
|
||||||
|
public class HttpBasicIdentity : GenericIdentity
|
||||||
|
{
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
private string _password;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region internal Constructors
|
||||||
|
|
||||||
|
internal HttpBasicIdentity (string username, string password)
|
||||||
|
: base (username, "Basic")
|
||||||
|
{
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the password from an HTTP Basic authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the password.
|
||||||
|
/// </value>
|
||||||
|
public virtual string Password {
|
||||||
|
get {
|
||||||
|
return _password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,185 @@
|
|||||||
|
#region License
|
||||||
|
/*
|
||||||
|
* HttpDigestIdentity.cs
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 sta.blockhead
|
||||||
|
*
|
||||||
|
* 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 without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Security.Principal;
|
||||||
|
|
||||||
|
namespace WebSocketSharp.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the user name and other authentication parameters from an HTTP Digest
|
||||||
|
/// authentication request.
|
||||||
|
/// </summary>
|
||||||
|
public class HttpDigestIdentity : GenericIdentity
|
||||||
|
{
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
private NameValueCollection _params;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal Constructors
|
||||||
|
|
||||||
|
internal HttpDigestIdentity (NameValueCollection authParams)
|
||||||
|
: base (authParams ["username"], "Digest")
|
||||||
|
{
|
||||||
|
_params = authParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the algorithm parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the algorithm parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Algorithm {
|
||||||
|
get {
|
||||||
|
return _params ["algorithm"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cnonce parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the cnonce parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Cnonce {
|
||||||
|
get {
|
||||||
|
return _params ["cnonce"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the nc parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the nc parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Nc {
|
||||||
|
get {
|
||||||
|
return _params ["nc"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the nonce parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the nonce parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Nonce {
|
||||||
|
get {
|
||||||
|
return _params ["nonce"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the opaque parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the opaque parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Opaque {
|
||||||
|
get {
|
||||||
|
return _params ["opaque"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the qop parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the qop parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Qop {
|
||||||
|
get {
|
||||||
|
return _params ["qop"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the realm parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the realm parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Realm {
|
||||||
|
get {
|
||||||
|
return _params ["realm"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the response parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the response parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Response {
|
||||||
|
get {
|
||||||
|
return _params ["response"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the uri parameter from an HTTP Digest authentication request.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the uri parameter.
|
||||||
|
/// </value>
|
||||||
|
public string Uri {
|
||||||
|
get {
|
||||||
|
return _params ["uri"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal Methods
|
||||||
|
|
||||||
|
internal bool IsValid (
|
||||||
|
string password, string realm, string method, string entity)
|
||||||
|
{
|
||||||
|
var parameters = new NameValueCollection (_params);
|
||||||
|
parameters ["password"] = password;
|
||||||
|
parameters ["realm"] = realm;
|
||||||
|
parameters ["method"] = method;
|
||||||
|
parameters ["entity"] = entity;
|
||||||
|
|
||||||
|
return _params ["response"] == HttpUtility.CreateRequestDigest (parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,222 +1,200 @@
|
|||||||
//
|
#region License
|
||||||
// ListenerAsyncResult.cs
|
/*
|
||||||
// Copied from System.Net.ListenerAsyncResult.cs
|
* ListenerAsyncResult.cs
|
||||||
//
|
*
|
||||||
// Authors:
|
* This code is derived from System.Net.ListenerAsyncResult.cs of Mono
|
||||||
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
|
* (http://www.mono-project.com).
|
||||||
//
|
*
|
||||||
// Copyright (c) 2005 Ximian, Inc (http://www.ximian.com)
|
* The MIT License
|
||||||
//
|
*
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
* Copyright (c) 2005 Ximian, Inc. (http://www.ximian.com)
|
||||||
// a copy of this software and associated documentation files (the
|
* Copyright (c) 2012-2013 sta.blockhead
|
||||||
// "Software"), to deal in the Software without restriction, including
|
*
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
* in the Software without restriction, including without limitation the rights
|
||||||
// the following conditions:
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
// The above copyright notice and this permission notice shall be
|
* furnished to do so, subject to the following conditions:
|
||||||
// included in all copies or substantial portions of the Software.
|
*
|
||||||
//
|
* The above copyright notice and this permission notice shall be included in
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* all copies or substantial portions of the Software.
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
*
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Authors
|
||||||
|
/*
|
||||||
|
* Authors:
|
||||||
|
* Gonzalo Paniagua Javier <gonzalo@ximian.com>
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace WebSocketSharp.Net {
|
namespace WebSocketSharp.Net
|
||||||
|
{
|
||||||
class ListenerAsyncResult : IAsyncResult
|
internal class ListenerAsyncResult : IAsyncResult
|
||||||
{
|
{
|
||||||
#region Private Static Field
|
#region Private Fields
|
||||||
|
|
||||||
static WaitCallback InvokeCB = new WaitCallback (InvokeCallback);
|
private AsyncCallback _callback;
|
||||||
|
private bool _completed;
|
||||||
#endregion
|
private HttpListenerContext _context;
|
||||||
|
private Exception _exception;
|
||||||
#region Private Fields
|
private ManualResetEvent _waitHandle;
|
||||||
|
private object _state;
|
||||||
AsyncCallback cb;
|
private object _sync;
|
||||||
bool completed;
|
private bool _syncCompleted;
|
||||||
HttpListenerContext context;
|
|
||||||
Exception exception;
|
#endregion
|
||||||
ListenerAsyncResult forward;
|
|
||||||
ManualResetEvent handle;
|
#region Internal Fields
|
||||||
object locker;
|
|
||||||
object state;
|
internal bool EndCalled;
|
||||||
bool synch;
|
internal bool InGet;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Fields
|
#region Public Constructors
|
||||||
|
|
||||||
internal bool EndCalled;
|
public ListenerAsyncResult (AsyncCallback callback, object state)
|
||||||
internal bool InGet;
|
{
|
||||||
|
_callback = callback;
|
||||||
#endregion
|
_state = state;
|
||||||
|
_sync = new object ();
|
||||||
#region Constructor
|
}
|
||||||
|
|
||||||
public ListenerAsyncResult (AsyncCallback cb, object state)
|
#endregion
|
||||||
{
|
|
||||||
this.cb = cb;
|
#region Public Properties
|
||||||
this.state = state;
|
|
||||||
this.locker = new object();
|
public object AsyncState {
|
||||||
}
|
get {
|
||||||
|
return _state;
|
||||||
#endregion
|
}
|
||||||
|
}
|
||||||
#region Properties
|
|
||||||
|
public WaitHandle AsyncWaitHandle {
|
||||||
public object AsyncState {
|
get {
|
||||||
get {
|
lock (_sync)
|
||||||
if (forward != null)
|
return _waitHandle ?? (_waitHandle = new ManualResetEvent (_completed));
|
||||||
return forward.AsyncState;
|
}
|
||||||
|
}
|
||||||
return state;
|
|
||||||
}
|
public bool CompletedSynchronously {
|
||||||
}
|
get {
|
||||||
|
return _syncCompleted;
|
||||||
public WaitHandle AsyncWaitHandle {
|
}
|
||||||
get {
|
}
|
||||||
if (forward != null)
|
|
||||||
return forward.AsyncWaitHandle;
|
public bool IsCompleted {
|
||||||
|
get {
|
||||||
lock (locker) {
|
lock (_sync)
|
||||||
if (handle == null)
|
return _completed;
|
||||||
handle = new ManualResetEvent (completed);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return handle;
|
#endregion
|
||||||
}
|
|
||||||
}
|
#region Private Methods
|
||||||
|
|
||||||
public bool CompletedSynchronously {
|
private static void invokeCallback (object state)
|
||||||
get {
|
{
|
||||||
if (forward != null)
|
try {
|
||||||
return forward.CompletedSynchronously;
|
var ares = (ListenerAsyncResult) state;
|
||||||
|
ares._callback (ares);
|
||||||
return synch;
|
}
|
||||||
}
|
catch {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public bool IsCompleted {
|
|
||||||
get {
|
#endregion
|
||||||
if (forward != null)
|
|
||||||
return forward.IsCompleted;
|
#region Internal Methods
|
||||||
|
|
||||||
lock (locker) {
|
internal void Complete (Exception exception)
|
||||||
return completed;
|
{
|
||||||
}
|
_exception = InGet && (exception is ObjectDisposedException)
|
||||||
}
|
? new HttpListenerException (500, "Listener closed")
|
||||||
}
|
: exception;
|
||||||
|
|
||||||
#endregion
|
lock (_sync) {
|
||||||
|
_completed = true;
|
||||||
#region Private Method
|
if (_waitHandle != null)
|
||||||
|
_waitHandle.Set ();
|
||||||
static void InvokeCallback (object o)
|
|
||||||
{
|
if (_callback != null)
|
||||||
ListenerAsyncResult ares = (ListenerAsyncResult) o;
|
ThreadPool.UnsafeQueueUserWorkItem (invokeCallback, this);
|
||||||
if (ares.forward != null) {
|
}
|
||||||
InvokeCallback (ares.forward);
|
}
|
||||||
return;
|
|
||||||
}
|
internal void Complete (HttpListenerContext context)
|
||||||
|
{
|
||||||
try {
|
Complete (context, false);
|
||||||
ares.cb (ares);
|
}
|
||||||
} catch {
|
|
||||||
}
|
internal void Complete (HttpListenerContext context, bool syncCompleted)
|
||||||
}
|
{
|
||||||
|
var listener = context.Listener;
|
||||||
#endregion
|
var scheme = listener.SelectAuthenticationScheme (context);
|
||||||
|
if (scheme == AuthenticationSchemes.None) {
|
||||||
#region Internal Methods
|
context.Response.Close (HttpStatusCode.Forbidden);
|
||||||
|
listener.BeginGetContext (this);
|
||||||
internal void Complete (Exception exc)
|
|
||||||
{
|
return;
|
||||||
if (forward != null) {
|
}
|
||||||
forward.Complete (exc);
|
|
||||||
return;
|
var header = context.Request.Headers ["Authorization"];
|
||||||
}
|
if (scheme == AuthenticationSchemes.Basic &&
|
||||||
|
(header == null ||
|
||||||
exception = exc;
|
!header.StartsWith ("basic", StringComparison.OrdinalIgnoreCase))) {
|
||||||
if (InGet && (exc is ObjectDisposedException))
|
context.Response.CloseWithAuthChallenge (
|
||||||
exception = new HttpListenerException (500, "Listener closed");
|
HttpUtility.CreateBasicAuthChallenge (listener.Realm));
|
||||||
|
listener.BeginGetContext (this);
|
||||||
lock (locker) {
|
|
||||||
completed = true;
|
return;
|
||||||
if (handle != null)
|
}
|
||||||
handle.Set ();
|
|
||||||
|
if (scheme == AuthenticationSchemes.Digest &&
|
||||||
if (cb != null)
|
(header == null ||
|
||||||
ThreadPool.UnsafeQueueUserWorkItem (InvokeCB, this);
|
!header.StartsWith ("digest", StringComparison.OrdinalIgnoreCase))) {
|
||||||
}
|
context.Response.CloseWithAuthChallenge (
|
||||||
}
|
HttpUtility.CreateDigestAuthChallenge (listener.Realm));
|
||||||
|
listener.BeginGetContext (this);
|
||||||
internal void Complete (HttpListenerContext context)
|
|
||||||
{
|
return;
|
||||||
Complete (context, false);
|
}
|
||||||
}
|
|
||||||
|
_context = context;
|
||||||
internal void Complete (HttpListenerContext context, bool synch)
|
_syncCompleted = syncCompleted;
|
||||||
{
|
|
||||||
if (forward != null) {
|
lock (_sync) {
|
||||||
forward.Complete (context, synch);
|
_completed = true;
|
||||||
return;
|
if (_waitHandle != null)
|
||||||
}
|
_waitHandle.Set ();
|
||||||
|
|
||||||
this.synch = synch;
|
if (_callback != null)
|
||||||
this.context = context;
|
ThreadPool.UnsafeQueueUserWorkItem (invokeCallback, this);
|
||||||
lock (locker) {
|
}
|
||||||
AuthenticationSchemes schemes = context.Listener.SelectAuthenticationScheme (context);
|
}
|
||||||
if ((schemes == AuthenticationSchemes.Basic || context.Listener.AuthenticationSchemes == AuthenticationSchemes.Negotiate) && context.Request.Headers ["Authorization"] == null) {
|
|
||||||
context.Response.StatusCode = 401;
|
internal HttpListenerContext GetContext ()
|
||||||
context.Response.Headers ["WWW-Authenticate"] = schemes + " realm=\"" + context.Listener.Realm + "\"";
|
{
|
||||||
context.Response.OutputStream.Close ();
|
if (_exception != null)
|
||||||
IAsyncResult ares = context.Listener.BeginGetContext (cb, state);
|
throw _exception;
|
||||||
this.forward = (ListenerAsyncResult) ares;
|
|
||||||
lock (forward.locker) {
|
return _context;
|
||||||
if (handle != null)
|
}
|
||||||
forward.handle = handle;
|
|
||||||
}
|
#endregion
|
||||||
|
}
|
||||||
ListenerAsyncResult next = forward;
|
|
||||||
for (int i = 0; next.forward != null; i++) {
|
|
||||||
if (i > 20)
|
|
||||||
Complete (new HttpListenerException (400, "Too many authentication errors"));
|
|
||||||
|
|
||||||
next = next.forward;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completed = true;
|
|
||||||
if (handle != null)
|
|
||||||
handle.Set ();
|
|
||||||
|
|
||||||
if (cb != null)
|
|
||||||
ThreadPool.UnsafeQueueUserWorkItem (InvokeCB, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal HttpListenerContext GetContext ()
|
|
||||||
{
|
|
||||||
if (forward != null)
|
|
||||||
return forward.GetContext ();
|
|
||||||
|
|
||||||
if (exception != null)
|
|
||||||
throw exception;
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,179 @@
|
|||||||
|
#region License
|
||||||
|
/*
|
||||||
|
* NetworkCredential.cs
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 sta.blockhead
|
||||||
|
*
|
||||||
|
* 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 without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WebSocketSharp.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the credentials for HTTP authentication (Basic/Digest).
|
||||||
|
/// </summary>
|
||||||
|
public class NetworkCredential
|
||||||
|
{
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
private string _domain;
|
||||||
|
private string _password;
|
||||||
|
private string [] _roles;
|
||||||
|
private string _username;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NetworkCredential"/> class
|
||||||
|
/// with the specified user name and password.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">
|
||||||
|
/// A <see cref="string"/> that represents the user name associated with the
|
||||||
|
/// credentials.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="password">
|
||||||
|
/// A <see cref="string"/> that represents the password for the user name
|
||||||
|
/// associated with the credentials.
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// <paramref name="username"/> is <see langword="null"/> or empty.
|
||||||
|
/// </exception>
|
||||||
|
public NetworkCredential (string username, string password)
|
||||||
|
: this (username, password, null, new string [0])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NetworkCredential"/> class
|
||||||
|
/// with the specified user name, password, domain, and roles.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">
|
||||||
|
/// A <see cref="string"/> that represents the user name associated with the
|
||||||
|
/// credentials.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="password">
|
||||||
|
/// A <see cref="string"/> that represents the password for the user name
|
||||||
|
/// associated with the credentials.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="domain">
|
||||||
|
/// A <see cref="string"/> that represents the name of the user domain
|
||||||
|
/// associated with the credentials.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="roles">
|
||||||
|
/// An array of <see cref="string"/> that contains the role names to which
|
||||||
|
/// the user associated with the credentials belongs if any.
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// <paramref name="username"/> is <see langword="null"/> or empty.
|
||||||
|
/// </exception>
|
||||||
|
public NetworkCredential (
|
||||||
|
string username, string password, string domain, params string [] roles)
|
||||||
|
{
|
||||||
|
if (username == null || username.Length == 0)
|
||||||
|
throw new ArgumentException ("Must not be null or empty.", "username");
|
||||||
|
|
||||||
|
_username = username;
|
||||||
|
_password = password;
|
||||||
|
_domain = domain;
|
||||||
|
_roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the user domain associated with the credentials.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the name of the user domain
|
||||||
|
/// associated with the credentials.
|
||||||
|
/// </value>
|
||||||
|
public string Domain {
|
||||||
|
get {
|
||||||
|
return _domain ?? String.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal set {
|
||||||
|
_domain = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the password for the user name associated with the credentials.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the password for the user name
|
||||||
|
/// associated with the credentials.
|
||||||
|
/// </value>
|
||||||
|
public string Password {
|
||||||
|
get {
|
||||||
|
return _password ?? String.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal set {
|
||||||
|
_password = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the role names to which the user associated with the credentials
|
||||||
|
/// belongs.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// An array of <see cref="string"/> that contains the role names to which
|
||||||
|
/// the user associated with the credentials belongs.
|
||||||
|
/// </value>
|
||||||
|
public string [] Roles {
|
||||||
|
get {
|
||||||
|
return _roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal set {
|
||||||
|
_roles = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the user name associated with the credentials.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A <see cref="string"/> that represents the user name associated with the
|
||||||
|
/// credentials.
|
||||||
|
/// </value>
|
||||||
|
public string UserName {
|
||||||
|
get {
|
||||||
|
return _username;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal set {
|
||||||
|
_username = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,253 +1,281 @@
|
|||||||
//
|
#region License
|
||||||
// RequestStream.cs
|
/*
|
||||||
// Copied from System.Net.RequestStream.cs
|
* RequestStream.cs
|
||||||
//
|
*
|
||||||
// Author:
|
* This code is derived from System.Net.RequestStream.cs of Mono
|
||||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
* (http://www.mono-project.com).
|
||||||
//
|
*
|
||||||
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
* The MIT License
|
||||||
//
|
*
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||||||
// a copy of this software and associated documentation files (the
|
* Copyright (c) 2012-2013 sta.blockhead
|
||||||
// "Software"), to deal in the Software without restriction, including
|
*
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
* in the Software without restriction, including without limitation the rights
|
||||||
// the following conditions:
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
// The above copyright notice and this permission notice shall be
|
* furnished to do so, subject to the following conditions:
|
||||||
// included in all copies or substantial portions of the Software.
|
*
|
||||||
//
|
* The above copyright notice and this permission notice shall be included in
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* all copies or substantial portions of the Software.
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
*
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Authors
|
||||||
|
/*
|
||||||
|
* Authors:
|
||||||
|
* Gonzalo Paniagua Javier <gonzalo@novell.com>
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace WebSocketSharp.Net {
|
namespace WebSocketSharp.Net
|
||||||
|
{
|
||||||
class RequestStream : Stream {
|
internal class RequestStream : Stream
|
||||||
|
{
|
||||||
#region Fields
|
#region Private Fields
|
||||||
|
|
||||||
byte [] buffer;
|
private byte [] _buffer;
|
||||||
bool disposed;
|
private bool _disposed;
|
||||||
int length;
|
private int _length;
|
||||||
int offset;
|
private int _offset;
|
||||||
long remaining_body;
|
private long _remainingBody;
|
||||||
Stream stream;
|
private Stream _stream;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Internal Constructors
|
||||||
|
|
||||||
internal RequestStream (Stream stream, byte [] buffer, int offset, int length)
|
internal RequestStream (
|
||||||
: this (stream, buffer, offset, length, -1)
|
Stream stream, byte [] buffer, int offset, int length)
|
||||||
{
|
: this (stream, buffer, offset, length, -1)
|
||||||
}
|
{
|
||||||
|
}
|
||||||
internal RequestStream (Stream stream, byte [] buffer, int offset, int length, long contentlength)
|
|
||||||
{
|
internal RequestStream (
|
||||||
this.stream = stream;
|
Stream stream, byte [] buffer, int offset, int length, long contentlength)
|
||||||
this.buffer = buffer;
|
{
|
||||||
this.offset = offset;
|
_stream = stream;
|
||||||
this.length = length;
|
_buffer = buffer;
|
||||||
this.remaining_body = contentlength;
|
_offset = offset;
|
||||||
}
|
_length = length;
|
||||||
|
_remainingBody = contentlength;
|
||||||
#endregion
|
}
|
||||||
|
|
||||||
#region Properties
|
#endregion
|
||||||
|
|
||||||
public override bool CanRead {
|
#region Public Properties
|
||||||
get { return true; }
|
|
||||||
}
|
public override bool CanRead {
|
||||||
|
get {
|
||||||
public override bool CanSeek {
|
return true;
|
||||||
get { return false; }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanWrite {
|
public override bool CanSeek {
|
||||||
get { return false; }
|
get {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
public override long Length {
|
}
|
||||||
get { throw new NotSupportedException (); }
|
|
||||||
}
|
public override bool CanWrite {
|
||||||
|
get {
|
||||||
public override long Position {
|
return false;
|
||||||
get { throw new NotSupportedException (); }
|
}
|
||||||
set { throw new NotSupportedException (); }
|
}
|
||||||
}
|
|
||||||
|
public override long Length {
|
||||||
#endregion
|
get {
|
||||||
|
throw new NotSupportedException ();
|
||||||
#region Private Method
|
}
|
||||||
|
}
|
||||||
// Returns 0 if we can keep reading from the base stream,
|
|
||||||
// > 0 if we read something from the buffer.
|
public override long Position {
|
||||||
// -1 if we had a content length set and we finished reading that many bytes.
|
get {
|
||||||
int FillFromBuffer (byte [] buffer, int offset, int count)
|
throw new NotSupportedException ();
|
||||||
{
|
}
|
||||||
if (buffer == null)
|
|
||||||
throw new ArgumentNullException ("buffer");
|
set {
|
||||||
|
throw new NotSupportedException ();
|
||||||
if (offset < 0)
|
}
|
||||||
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
}
|
||||||
|
|
||||||
if (count < 0)
|
#endregion
|
||||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
|
||||||
|
#region Private Methods
|
||||||
int len = buffer.Length;
|
|
||||||
if (offset > len)
|
// Returns 0 if we can keep reading from the base stream,
|
||||||
throw new ArgumentException ("Destination offset is beyond array size.");
|
// > 0 if we read something from the buffer.
|
||||||
|
// -1 if we had a content length set and we finished reading that many bytes.
|
||||||
if (offset > len - count)
|
private int fillFromBuffer (byte [] buffer, int offset, int count)
|
||||||
throw new ArgumentException ("Reading would overrun buffer.");
|
{
|
||||||
|
if (buffer == null)
|
||||||
if (this.remaining_body == 0)
|
throw new ArgumentNullException ("buffer");
|
||||||
return -1;
|
|
||||||
|
if (offset < 0)
|
||||||
if (this.length == 0)
|
throw new ArgumentOutOfRangeException ("offset", "Less than zero.");
|
||||||
return 0;
|
|
||||||
|
if (count < 0)
|
||||||
int size = Math.Min (this.length, count);
|
throw new ArgumentOutOfRangeException ("count", "Less than zero.");
|
||||||
if (this.remaining_body > 0)
|
|
||||||
size = (int) Math.Min (size, this.remaining_body);
|
var len = buffer.Length;
|
||||||
|
if (offset > len)
|
||||||
if (this.offset > this.buffer.Length - size) {
|
throw new ArgumentException ("'offset' is greater than 'buffer' size.");
|
||||||
size = Math.Min (size, this.buffer.Length - this.offset);
|
|
||||||
}
|
if (offset > len - count)
|
||||||
|
throw new ArgumentException ("Reading would overrun 'buffer'.");
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
if (_remainingBody == 0)
|
||||||
|
return -1;
|
||||||
Buffer.BlockCopy (this.buffer, this.offset, buffer, offset, size);
|
|
||||||
this.offset += size;
|
if (_length == 0)
|
||||||
this.length -= size;
|
return 0;
|
||||||
if (this.remaining_body > 0)
|
|
||||||
remaining_body -= size;
|
var size = _length < count ? _length : count;
|
||||||
|
if (_remainingBody > 0 && _remainingBody < size)
|
||||||
return size;
|
size = (int) _remainingBody;
|
||||||
}
|
|
||||||
|
var remainingBuffer = _buffer.Length - _offset;
|
||||||
#endregion
|
if (remainingBuffer < size)
|
||||||
|
size = remainingBuffer;
|
||||||
#region Public Methods
|
|
||||||
|
if (size == 0)
|
||||||
public override IAsyncResult BeginRead (
|
return 0;
|
||||||
byte [] buffer, int offset, int count, AsyncCallback cback, object state)
|
|
||||||
{
|
Buffer.BlockCopy (_buffer, _offset, buffer, offset, size);
|
||||||
if (disposed)
|
_offset += size;
|
||||||
throw new ObjectDisposedException (GetType ().ToString ());
|
_length -= size;
|
||||||
|
if (_remainingBody > 0)
|
||||||
int nread = FillFromBuffer (buffer, offset, count);
|
_remainingBody -= size;
|
||||||
if (nread > 0 || nread == -1) {
|
|
||||||
var ares = new HttpStreamAsyncResult ();
|
return size;
|
||||||
ares.Buffer = buffer;
|
}
|
||||||
ares.Offset = offset;
|
|
||||||
ares.Count = count;
|
#endregion
|
||||||
ares.Callback = cback;
|
|
||||||
ares.State = state;
|
#region Public Methods
|
||||||
ares.SyncRead = nread;
|
|
||||||
ares.Complete ();
|
public override IAsyncResult BeginRead (
|
||||||
return ares;
|
byte [] buffer,
|
||||||
}
|
int offset,
|
||||||
|
int count,
|
||||||
// Avoid reading past the end of the request to allow
|
AsyncCallback callback,
|
||||||
// for HTTP pipelining
|
object state)
|
||||||
if (remaining_body >= 0 && count > remaining_body)
|
{
|
||||||
count = (int) Math.Min (Int32.MaxValue, remaining_body);
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException (GetType ().ToString ());
|
||||||
return stream.BeginRead (buffer, offset, count, cback, state);
|
|
||||||
}
|
var read = fillFromBuffer (buffer, offset, count);
|
||||||
|
if (read > 0 || read == -1) {
|
||||||
public override IAsyncResult BeginWrite (
|
var ares = new HttpStreamAsyncResult ();
|
||||||
byte [] buffer, int offset, int count, AsyncCallback cback, object state)
|
ares.Buffer = buffer;
|
||||||
{
|
ares.Offset = offset;
|
||||||
throw new NotSupportedException ();
|
ares.Count = count;
|
||||||
}
|
ares.Callback = callback;
|
||||||
|
ares.State = state;
|
||||||
public override void Close ()
|
ares.SyncRead = read;
|
||||||
{
|
ares.Complete ();
|
||||||
disposed = true;
|
|
||||||
}
|
return ares;
|
||||||
|
}
|
||||||
public override int EndRead (IAsyncResult ares)
|
|
||||||
{
|
// Avoid reading past the end of the request to allow for HTTP pipelining.
|
||||||
if (disposed)
|
if (_remainingBody >= 0 && _remainingBody < count)
|
||||||
throw new ObjectDisposedException (GetType ().ToString ());
|
count = (int) _remainingBody;
|
||||||
|
|
||||||
if (ares == null)
|
return _stream.BeginRead (buffer, offset, count, callback, state);
|
||||||
throw new ArgumentNullException ("ares");
|
}
|
||||||
|
|
||||||
if (ares is HttpStreamAsyncResult) {
|
public override IAsyncResult BeginWrite (
|
||||||
var ares_ = (HttpStreamAsyncResult) ares;
|
byte [] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||||
if (!ares.IsCompleted)
|
{
|
||||||
ares.AsyncWaitHandle.WaitOne ();
|
throw new NotSupportedException ();
|
||||||
|
}
|
||||||
return ares_.SyncRead;
|
|
||||||
}
|
public override void Close ()
|
||||||
|
{
|
||||||
// Close on exception?
|
_disposed = true;
|
||||||
int nread = stream.EndRead (ares);
|
}
|
||||||
if (remaining_body > 0 && nread > 0)
|
|
||||||
remaining_body -= nread;
|
public override int EndRead (IAsyncResult asyncResult)
|
||||||
|
{
|
||||||
return nread;
|
if (_disposed)
|
||||||
}
|
throw new ObjectDisposedException (GetType ().ToString ());
|
||||||
|
|
||||||
public override void EndWrite (IAsyncResult async_result)
|
if (asyncResult == null)
|
||||||
{
|
throw new ArgumentNullException ("asyncResult");
|
||||||
throw new NotSupportedException ();
|
|
||||||
}
|
if (asyncResult is HttpStreamAsyncResult) {
|
||||||
|
var ares = (HttpStreamAsyncResult) asyncResult;
|
||||||
public override void Flush ()
|
if (!ares.IsCompleted)
|
||||||
{
|
ares.AsyncWaitHandle.WaitOne ();
|
||||||
}
|
|
||||||
|
return ares.SyncRead;
|
||||||
public override int Read ([In,Out] byte[] buffer, int offset, int count)
|
}
|
||||||
{
|
|
||||||
if (disposed)
|
// Close on exception?
|
||||||
throw new ObjectDisposedException (GetType () .ToString ());
|
var read = _stream.EndRead (asyncResult);
|
||||||
|
if (read > 0 && _remainingBody > 0)
|
||||||
// Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
|
_remainingBody -= read;
|
||||||
int nread = FillFromBuffer (buffer, offset, count);
|
|
||||||
if (nread == -1) { // No more bytes available (Content-Length)
|
return read;
|
||||||
return 0;
|
}
|
||||||
} else if (nread > 0) {
|
|
||||||
return nread;
|
public override void EndWrite (IAsyncResult asyncResult)
|
||||||
}
|
{
|
||||||
|
throw new NotSupportedException ();
|
||||||
nread = stream.Read (buffer, offset, count);
|
}
|
||||||
if (nread > 0 && remaining_body > 0)
|
|
||||||
remaining_body -= nread;
|
public override void Flush ()
|
||||||
|
{
|
||||||
return nread;
|
}
|
||||||
}
|
|
||||||
|
public override int Read (byte [] buffer, int offset, int count)
|
||||||
public override long Seek (long offset, SeekOrigin origin)
|
{
|
||||||
{
|
if (_disposed)
|
||||||
throw new NotSupportedException ();
|
throw new ObjectDisposedException (GetType ().ToString ());
|
||||||
}
|
|
||||||
|
// Call fillFromBuffer to check for buffer boundaries even when
|
||||||
public override void SetLength (long value)
|
// _remainingBody is 0.
|
||||||
{
|
var read = fillFromBuffer (buffer, offset, count);
|
||||||
throw new NotSupportedException ();
|
if (read == -1) // No more bytes available (Content-Length).
|
||||||
}
|
return 0;
|
||||||
|
else if (read > 0)
|
||||||
public override void Write (byte[] buffer, int offset, int count)
|
return read;
|
||||||
{
|
|
||||||
throw new NotSupportedException ();
|
read = _stream.Read (buffer, offset, count);
|
||||||
}
|
if (read > 0 && _remainingBody > 0)
|
||||||
|
_remainingBody -= read;
|
||||||
#endregion
|
|
||||||
}
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek (long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength (long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (byte [] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,284 +1,322 @@
|
|||||||
//
|
#region License
|
||||||
// ResponseStream.cs
|
/*
|
||||||
// Copied from System.Net.ResponseStream.cs
|
* ResponseStream.cs
|
||||||
//
|
*
|
||||||
// Author:
|
* This code is derived from System.Net.ResponseStream.cs of Mono
|
||||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
* (http://www.mono-project.com).
|
||||||
//
|
*
|
||||||
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
* The MIT License
|
||||||
//
|
*
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||||||
// a copy of this software and associated documentation files (the
|
* Copyright (c) 2012-2014 sta.blockhead
|
||||||
// "Software"), to deal in the Software without restriction, including
|
*
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
* in the Software without restriction, including without limitation the rights
|
||||||
// the following conditions:
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
// The above copyright notice and this permission notice shall be
|
* furnished to do so, subject to the following conditions:
|
||||||
// included in all copies or substantial portions of the Software.
|
*
|
||||||
//
|
* The above copyright notice and this permission notice shall be included in
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* all copies or substantial portions of the Software.
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
*
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* 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.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Authors
|
||||||
|
/*
|
||||||
|
* Authors:
|
||||||
|
* Gonzalo Paniagua Javier <gonzalo@novell.com>
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace WebSocketSharp.Net {
|
namespace WebSocketSharp.Net
|
||||||
|
{
|
||||||
// FIXME: Does this buffer the response until Close?
|
// FIXME: Does this buffer the response until Close?
|
||||||
// Update: we send a single packet for the first non-chunked Write
|
// Update: we send a single packet for the first non-chunked Write
|
||||||
// What happens when we set content-length to X and write X-1 bytes then close?
|
// What happens when we set content-length to X and write X-1 bytes then close?
|
||||||
// what if we don't set content-length at all?
|
// what if we don't set content-length at all?
|
||||||
class ResponseStream : Stream {
|
internal class ResponseStream : Stream
|
||||||
|
{
|
||||||
#region Private Static Field
|
#region Private Static Fields
|
||||||
|
|
||||||
static byte [] crlf = new byte [] { 13, 10 };
|
private static byte [] _crlf = new byte [] { 13, 10 };
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
bool disposed;
|
private bool _disposed;
|
||||||
bool ignore_errors;
|
private bool _ignoreErrors;
|
||||||
HttpListenerResponse response;
|
private HttpListenerResponse _response;
|
||||||
Stream stream;
|
private Stream _stream;
|
||||||
bool trailer_sent;
|
private bool _trailerSent;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructor
|
#region Internal Constructors
|
||||||
|
|
||||||
internal ResponseStream (System.IO.Stream stream, HttpListenerResponse response, bool ignore_errors)
|
internal ResponseStream (
|
||||||
{
|
Stream stream, HttpListenerResponse response, bool ignoreErrors)
|
||||||
this.stream = stream;
|
{
|
||||||
this.response = response;
|
_stream = stream;
|
||||||
this.ignore_errors = ignore_errors;
|
_response = response;
|
||||||
}
|
_ignoreErrors = ignoreErrors;
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
|
#endregion
|
||||||
#region Properties
|
|
||||||
|
#region Public Properties
|
||||||
public override bool CanRead {
|
|
||||||
get { return false; }
|
public override bool CanRead {
|
||||||
}
|
get {
|
||||||
|
return false;
|
||||||
public override bool CanSeek {
|
}
|
||||||
get { return false; }
|
}
|
||||||
}
|
|
||||||
|
public override bool CanSeek {
|
||||||
public override bool CanWrite {
|
get {
|
||||||
get { return true; }
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public override long Length {
|
|
||||||
get { throw new NotSupportedException (); }
|
public override bool CanWrite {
|
||||||
}
|
get {
|
||||||
|
return true;
|
||||||
public override long Position {
|
}
|
||||||
get { throw new NotSupportedException (); }
|
}
|
||||||
set { throw new NotSupportedException (); }
|
|
||||||
}
|
public override long Length {
|
||||||
|
get {
|
||||||
#endregion
|
throw new NotSupportedException ();
|
||||||
|
}
|
||||||
#region Private Methods
|
}
|
||||||
|
|
||||||
static byte [] GetChunkSizeBytes (int size, bool final)
|
public override long Position {
|
||||||
{
|
get {
|
||||||
string str = String.Format ("{0:x}\r\n{1}", size, final ? "\r\n" : "");
|
throw new NotSupportedException ();
|
||||||
return Encoding.ASCII.GetBytes (str);
|
}
|
||||||
}
|
|
||||||
|
set {
|
||||||
MemoryStream GetHeaders (bool closing)
|
throw new NotSupportedException ();
|
||||||
{
|
}
|
||||||
if (response.HeadersSent)
|
}
|
||||||
return null;
|
|
||||||
|
#endregion
|
||||||
MemoryStream ms = new MemoryStream ();
|
|
||||||
response.SendHeaders (closing, ms);
|
#region Private Methods
|
||||||
|
|
||||||
return ms;
|
private static byte [] getChunkSizeBytes (int size, bool final)
|
||||||
}
|
{
|
||||||
|
return Encoding.ASCII.GetBytes (
|
||||||
#endregion
|
String.Format ("{0:x}\r\n{1}", size, final ? "\r\n" : ""));
|
||||||
|
}
|
||||||
#region Internal Method
|
|
||||||
|
private MemoryStream getHeaders (bool closing)
|
||||||
internal void InternalWrite (byte [] buffer, int offset, int count)
|
{
|
||||||
{
|
if (_response.HeadersSent)
|
||||||
if (ignore_errors) {
|
return null;
|
||||||
try {
|
|
||||||
stream.Write (buffer, offset, count);
|
var stream = new MemoryStream ();
|
||||||
} catch {
|
_response.SendHeaders (closing, stream);
|
||||||
}
|
|
||||||
} else {
|
return stream;
|
||||||
stream.Write (buffer, offset, count);
|
}
|
||||||
}
|
|
||||||
}
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#region Internal Methods
|
||||||
|
|
||||||
#region Public Methods
|
internal void InternalWrite (byte [] buffer, int offset, int count)
|
||||||
|
{
|
||||||
public override IAsyncResult BeginRead (
|
if (_ignoreErrors) {
|
||||||
byte [] buffer,
|
try {
|
||||||
int offset,
|
_stream.Write (buffer, offset, count);
|
||||||
int count,
|
}
|
||||||
AsyncCallback cback,
|
catch {
|
||||||
object state)
|
}
|
||||||
{
|
}
|
||||||
throw new NotSupportedException ();
|
else {
|
||||||
}
|
_stream.Write (buffer, offset, count);
|
||||||
|
}
|
||||||
public override IAsyncResult BeginWrite (
|
}
|
||||||
byte [] buffer,
|
|
||||||
int offset,
|
#endregion
|
||||||
int count,
|
|
||||||
AsyncCallback cback,
|
#region Public Methods
|
||||||
object state)
|
|
||||||
{
|
public override IAsyncResult BeginRead (
|
||||||
if (disposed)
|
byte [] buffer,
|
||||||
throw new ObjectDisposedException (GetType ().ToString ());
|
int offset,
|
||||||
|
int count,
|
||||||
byte [] bytes = null;
|
AsyncCallback callback,
|
||||||
MemoryStream ms = GetHeaders (false);
|
object state)
|
||||||
bool chunked = response.SendChunked;
|
{
|
||||||
if (ms != null) {
|
throw new NotSupportedException ();
|
||||||
long start = ms.Position;
|
}
|
||||||
ms.Position = ms.Length;
|
|
||||||
if (chunked) {
|
public override IAsyncResult BeginWrite (
|
||||||
bytes = GetChunkSizeBytes (count, false);
|
byte [] buffer,
|
||||||
ms.Write (bytes, 0, bytes.Length);
|
int offset,
|
||||||
}
|
int count,
|
||||||
ms.Write (buffer, offset, count);
|
AsyncCallback callback,
|
||||||
buffer = ms.GetBuffer ();
|
object state)
|
||||||
offset = (int) start;
|
{
|
||||||
count = (int) (ms.Position - start);
|
if (_disposed)
|
||||||
} else if (chunked) {
|
throw new ObjectDisposedException (GetType ().ToString ());
|
||||||
bytes = GetChunkSizeBytes (count, false);
|
|
||||||
InternalWrite (bytes, 0, bytes.Length);
|
var stream = getHeaders (false);
|
||||||
}
|
var chunked = _response.SendChunked;
|
||||||
|
byte [] bytes = null;
|
||||||
return stream.BeginWrite (buffer, offset, count, cback, state);
|
if (stream != null) {
|
||||||
}
|
var start = stream.Position;
|
||||||
|
stream.Position = stream.Length;
|
||||||
public override void Close ()
|
if (chunked) {
|
||||||
{
|
bytes = getChunkSizeBytes (count, false);
|
||||||
if (disposed == false) {
|
stream.Write (bytes, 0, bytes.Length);
|
||||||
disposed = true;
|
}
|
||||||
byte [] bytes = null;
|
|
||||||
MemoryStream ms = GetHeaders (true);
|
stream.Write (buffer, offset, count);
|
||||||
bool chunked = response.SendChunked;
|
buffer = stream.GetBuffer ();
|
||||||
if (ms != null) {
|
offset = (int) start;
|
||||||
long start = ms.Position;
|
count = (int) (stream.Position - start);
|
||||||
if (chunked && !trailer_sent) {
|
}
|
||||||
bytes = GetChunkSizeBytes (0, true);
|
else if (chunked) {
|
||||||
ms.Position = ms.Length;
|
bytes = getChunkSizeBytes (count, false);
|
||||||
ms.Write (bytes, 0, bytes.Length);
|
InternalWrite (bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start));
|
|
||||||
trailer_sent = true;
|
return _stream.BeginWrite (buffer, offset, count, callback, state);
|
||||||
} else if (chunked && !trailer_sent) {
|
}
|
||||||
bytes = GetChunkSizeBytes (0, true);
|
|
||||||
InternalWrite (bytes, 0, bytes.Length);
|
public override void Close ()
|
||||||
trailer_sent = true;
|
{
|
||||||
}
|
if (_disposed)
|
||||||
|
return;
|
||||||
response.Close ();
|
|
||||||
}
|
_disposed = true;
|
||||||
}
|
|
||||||
|
var stream = getHeaders (true);
|
||||||
public override int EndRead (IAsyncResult ares)
|
var chunked = _response.SendChunked;
|
||||||
{
|
byte [] bytes = null;
|
||||||
throw new NotSupportedException ();
|
if (stream != null) {
|
||||||
}
|
var start = stream.Position;
|
||||||
|
if (chunked && !_trailerSent) {
|
||||||
public override void EndWrite (IAsyncResult ares)
|
bytes = getChunkSizeBytes (0, true);
|
||||||
{
|
stream.Position = stream.Length;
|
||||||
if (disposed)
|
stream.Write (bytes, 0, bytes.Length);
|
||||||
throw new ObjectDisposedException (GetType ().ToString ());
|
}
|
||||||
|
|
||||||
if (ignore_errors) {
|
InternalWrite (
|
||||||
try {
|
stream.GetBuffer (), (int) start, (int) (stream.Length - start));
|
||||||
stream.EndWrite (ares);
|
_trailerSent = true;
|
||||||
if (response.SendChunked)
|
}
|
||||||
stream.Write (crlf, 0, 2);
|
else if (chunked && !_trailerSent) {
|
||||||
} catch {
|
bytes = getChunkSizeBytes (0, true);
|
||||||
}
|
InternalWrite (bytes, 0, bytes.Length);
|
||||||
} else {
|
_trailerSent = true;
|
||||||
stream.EndWrite (ares);
|
}
|
||||||
if (response.SendChunked)
|
|
||||||
stream.Write (crlf, 0, 2);
|
_response.Close ();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public override int EndRead (IAsyncResult asyncResult)
|
||||||
public override void Flush ()
|
{
|
||||||
{
|
throw new NotSupportedException ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read ([In,Out] byte[] buffer, int offset, int count)
|
public override void EndWrite (IAsyncResult asyncResult)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException ();
|
if (_disposed)
|
||||||
}
|
throw new ObjectDisposedException (GetType ().ToString ());
|
||||||
|
|
||||||
public override long Seek (long offset, SeekOrigin origin)
|
Action<IAsyncResult> endWrite = ares => {
|
||||||
{
|
_stream.EndWrite (ares);
|
||||||
throw new NotSupportedException ();
|
if (_response.SendChunked)
|
||||||
}
|
_stream.Write (_crlf, 0, 2);
|
||||||
|
};
|
||||||
public override void SetLength (long value)
|
|
||||||
{
|
if (_ignoreErrors) {
|
||||||
throw new NotSupportedException ();
|
try {
|
||||||
}
|
endWrite (asyncResult);
|
||||||
|
}
|
||||||
public override void Write (byte [] buffer, int offset, int count)
|
catch {
|
||||||
{
|
}
|
||||||
if (disposed)
|
}
|
||||||
throw new ObjectDisposedException (GetType ().ToString ());
|
else {
|
||||||
|
endWrite (asyncResult);
|
||||||
byte [] bytes = null;
|
}
|
||||||
MemoryStream ms = GetHeaders (false);
|
}
|
||||||
bool chunked = response.SendChunked;
|
|
||||||
if (ms != null) {
|
public override void Flush ()
|
||||||
long start = ms.Position; // After the possible preamble for the encoding
|
{
|
||||||
ms.Position = ms.Length;
|
}
|
||||||
if (chunked) {
|
|
||||||
bytes = GetChunkSizeBytes (count, false);
|
public override int Read (byte [] buffer, int offset, int count)
|
||||||
ms.Write (bytes, 0, bytes.Length);
|
{
|
||||||
}
|
throw new NotSupportedException ();
|
||||||
|
}
|
||||||
int new_count = Math.Min (count, 16384 - (int) ms.Position + (int) start);
|
|
||||||
ms.Write (buffer, offset, new_count);
|
public override long Seek (long offset, SeekOrigin origin)
|
||||||
count -= new_count;
|
{
|
||||||
offset += new_count;
|
throw new NotSupportedException ();
|
||||||
InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start));
|
}
|
||||||
ms.SetLength (0);
|
|
||||||
ms.Capacity = 0; // 'dispose' the buffer in ms.
|
public override void SetLength (long value)
|
||||||
} else if (chunked) {
|
{
|
||||||
bytes = GetChunkSizeBytes (count, false);
|
throw new NotSupportedException ();
|
||||||
InternalWrite (bytes, 0, bytes.Length);
|
}
|
||||||
}
|
|
||||||
|
public override void Write (byte [] buffer, int offset, int count)
|
||||||
if (count > 0)
|
{
|
||||||
InternalWrite (buffer, offset, count);
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException (GetType ().ToString ());
|
||||||
if (chunked)
|
|
||||||
InternalWrite (crlf, 0, 2);
|
var stream = getHeaders (false);
|
||||||
}
|
var chunked = _response.SendChunked;
|
||||||
|
byte [] bytes = null;
|
||||||
#endregion
|
if (stream != null) {
|
||||||
}
|
// After the possible preamble for the encoding.
|
||||||
|
var start = stream.Position;
|
||||||
|
stream.Position = stream.Length;
|
||||||
|
if (chunked) {
|
||||||
|
bytes = getChunkSizeBytes (count, false);
|
||||||
|
stream.Write (bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newCount = Math.Min (
|
||||||
|
count, 16384 - (int) stream.Position + (int) start);
|
||||||
|
stream.Write (buffer, offset, newCount);
|
||||||
|
count -= newCount;
|
||||||
|
offset += newCount;
|
||||||
|
InternalWrite (
|
||||||
|
stream.GetBuffer (), (int) start, (int) (stream.Length - start));
|
||||||
|
stream.SetLength (0);
|
||||||
|
stream.Capacity = 0; // 'dispose' the buffer in stream.
|
||||||
|
}
|
||||||
|
else if (chunked) {
|
||||||
|
bytes = getChunkSizeBytes (count, false);
|
||||||
|
InternalWrite (bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
InternalWrite (buffer, offset, count);
|
||||||
|
|
||||||
|
if (chunked)
|
||||||
|
InternalWrite (_crlf, 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,119 +0,0 @@
|
|||||||
#region License
|
|
||||||
/*
|
|
||||||
* WsCredential.cs
|
|
||||||
*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013 sta.blockhead
|
|
||||||
*
|
|
||||||
* 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 without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE 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.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace WebSocketSharp {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides the credentials for HTTP authentication (Basic/Digest).
|
|
||||||
/// </summary>
|
|
||||||
public class WsCredential {
|
|
||||||
|
|
||||||
#region Private Fields
|
|
||||||
|
|
||||||
string _domain;
|
|
||||||
string _password;
|
|
||||||
string _userName;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Internal Constructors
|
|
||||||
|
|
||||||
internal WsCredential()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal WsCredential(string userName, string password)
|
|
||||||
: this(userName, password, null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal WsCredential(string userName, string password, string domain)
|
|
||||||
{
|
|
||||||
_userName = userName;
|
|
||||||
_password = password;
|
|
||||||
_domain = domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the user domain associated with the credentials.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// A <see cref="string"/> that contains the name of the user domain associated with the credentials.
|
|
||||||
/// Currently, returns the request uri of a WebSocket opening handshake.
|
|
||||||
/// </value>
|
|
||||||
public string Domain {
|
|
||||||
get {
|
|
||||||
return _domain ?? String.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal set {
|
|
||||||
_domain = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the password for the user name associated with the credentials.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// A <see cref="string"/> that contains the password for the user name associated with the credentials.
|
|
||||||
/// </value>
|
|
||||||
public string Password {
|
|
||||||
get {
|
|
||||||
return _password ?? String.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal set {
|
|
||||||
_password = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the user name associated with the credentials.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// A <see cref="string"/> that contains the user name associated with the credentials.
|
|
||||||
/// </value>
|
|
||||||
public string UserName {
|
|
||||||
get {
|
|
||||||
return _userName ?? String.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal set {
|
|
||||||
_userName = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue