// System.Net.HttpConnection
//
// Author:
-// Gonzalo Paniagua Javier (gonzalo@novell.com)
+// Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
//
-// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2005-2009 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2012 Xamarin, Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
#if SECURITY_DEP
+extern alias MonoSecurity;
+
using System.IO;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
-using Mono.Security.Protocol.Tls;
+using MonoSecurity::Mono.Security.Protocol.Tls;
namespace System.Net {
sealed class HttpConnection
Timer timer;
IPEndPoint local_ep;
HttpListener last_listener;
+ int [] client_cert_errors;
+ X509Certificate2 client_cert;
public HttpConnection (Socket sock, EndPointListener epl, bool secure, X509Certificate2 cert, AsymmetricAlgorithm key)
{
if (secure == false) {
stream = new NetworkStream (sock, false);
} else {
- SslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, false);
+ SslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, true, false);
ssl_stream.PrivateKeyCertSelectionDelegate += OnPVKSelection;
+ ssl_stream.ClientCertValidationDelegate += OnClientCertificateValidation;
stream = ssl_stream;
}
timer = new Timer (OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
Init ();
}
+ internal int [] ClientCertificateErrors {
+ get { return client_cert_errors; }
+ }
+
+ internal X509Certificate2 ClientCertificate {
+ get { return client_cert; }
+ }
+
+ bool OnClientCertificateValidation (X509Certificate certificate, int[] errors)
+ {
+ if (certificate == null)
+ return true;
+ X509Certificate2 cert = certificate as X509Certificate2;
+ if (cert == null)
+ cert = new X509Certificate2 (certificate.GetRawCertData ());
+ client_cert = cert;
+ client_cert_errors = errors;
+ return true;
+ }
+
AsymmetricAlgorithm OnPVKSelection (X509Certificate certificate, string targetHost)
{
return key;
} catch {
timer.Change (Timeout.Infinite, Timeout.Infinite);
CloseSocket ();
+ Unbind ();
}
}
} catch {
if (ms != null && ms.Length > 0)
SendError ();
- if (sock != null)
+ if (sock != null) {
CloseSocket ();
+ Unbind ();
+ }
return;
}
//if (ms.Length > 0)
// SendError (); // Why bother?
CloseSocket ();
+ Unbind ();
return;
}
if (!epl.BindContext (context)) {
SendError ("Invalid host", 400);
Close (true);
+ return;
}
- if (last_listener == null)
- epl.RemoveConnection (this);
- else
- last_listener.RemoveConnection (this);
-
- if (context.Listener != null) {
- context.Listener.AddConnection (this);
- context_bound = true;
+ HttpListener listener = context.Listener;
+ if (last_listener != listener) {
+ RemoveConnection ();
+ listener.AddConnection (this);
+ last_listener = listener;
}
- last_listener = context.Listener;
+
+ context_bound = true;
+ listener.RegisterContext (context);
return;
}
stream.BeginRead (buffer, 0, BufferSize, onread_cb, this);
}
+ void RemoveConnection ()
+ {
+ if (last_listener == null)
+ epl.RemoveConnection (this);
+ else
+ last_listener.RemoveConnection (this);
+ }
+
enum InputState {
RequestLine,
Headers
void Unbind ()
{
if (context_bound) {
- context.Listener.RemoveConnection (this);
epl.UnbindContext (context);
context_bound = false;
}
} finally {
sock = null;
}
- if (last_listener == null)
- epl.RemoveConnection (this);
+ RemoveConnection ();
}
internal void Close (bool force_close)
{
if (sock != null) {
Stream st = GetResponseStream ();
- st.Close ();
+ if (st != null)
+ st.Close ();
+
o_stream = null;
}
s.Close ();
}
Unbind ();
- if (last_listener == null)
- epl.RemoveConnection (this);
+ RemoveConnection ();
return;
}
}