Merge pull request #981 from methane/websocket
[mono.git] / mcs / class / System / System.Net / HttpListenerRequest.cs
index 39a6cf1f41488ad4b12e52c14238ca6c1b2b9cfe..37be80f1b94cc425d25146785eb129a14f144912 100644 (file)
@@ -1,10 +1,12 @@
 //
 // System.Net.HttpListenerRequest
 //
-// Author:
-//     Gonzalo Paniagua Javier (gonzalo@novell.com)
+// Authors:
+//     Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
+//     Marek Safar (marek.safar@gmail.com)
 //
 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2011-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
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_2_0 && SECURITY_DEP
+#if SECURITY_DEP
+
+#if MONOTOUCH || MONODROID
+using Mono.Security.Protocol.Tls;
+#else
+extern alias MonoSecurity;
+using MonoSecurity::Mono.Security.Protocol.Tls;
+#endif
 
 using System.Collections;
 using System.Collections.Specialized;
@@ -34,12 +43,27 @@ using System.Globalization;
 using System.IO;
 using System.Security.Cryptography.X509Certificates;
 using System.Text;
+#if NET_4_0
+using System.Security.Authentication.ExtendedProtection;
+#endif
+#if NET_4_5
+using System.Threading.Tasks;
+#endif
+
 namespace System.Net {
        public sealed class HttpListenerRequest
        {
+#if NET_4_0
+               class Context : TransportContext
+               {
+                       public override ChannelBinding GetChannelBinding (ChannelBindingKind kind)
+                       {
+                               throw new NotImplementedException ();
+                       }
+               }
+#endif
+
                string [] accept_types;
-//             int client_cert_error;
-//             bool no_get_certificate;
                Encoding content_encoding;
                long content_length;
                bool cl_set;
@@ -57,6 +81,9 @@ namespace System.Net {
                bool is_chunked;
                bool ka_set;
                bool keep_alive;
+               delegate X509Certificate2 GCCDelegate ();
+               GCCDelegate gcc_delegate;
+
                static byte [] _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
 
                internal HttpListenerRequest (HttpListenerContext context)
@@ -297,7 +324,10 @@ namespace System.Net {
                        while (true) {
                                // TODO: test if MS has a timeout when doing this
                                try {
-                                       if (InputStream.Read (bytes, 0, length) <= 0)
+                                       IAsyncResult ares = InputStream.BeginRead (bytes, 0, length, null, null);
+                                       if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (1000))
+                                               return false;
+                                       if (InputStream.EndRead (ares) <= 0)
                                                return true;
                                } catch {
                                        return false;
@@ -309,15 +339,14 @@ namespace System.Net {
                        get { return accept_types; }
                }
 
-               [MonoTODO ("Always returns 0")]
                public int ClientCertificateError {
                        get {
-/*                             
-                               if (no_get_certificate)
-                                       throw new InvalidOperationException (
-                                               "Call GetClientCertificate() before calling this method.");
-                               return client_cert_error;
-*/
+                               HttpConnection cnc = context.Connection;
+                               if (cnc.ClientCertificate == null)
+                                       throw new InvalidOperationException ("No client certificate");
+                               int [] errors = cnc.ClientCertificateErrors;
+                               if (errors != null && errors.Length > 0)
+                                       return errors [0];
                                return 0;
                        }
                }
@@ -457,23 +486,62 @@ namespace System.Net {
                        get { return user_languages; }
                }
 
-               public IAsyncResult BeginGetClientCertificate (AsyncCallback requestCallback, Object state)
+               public IAsyncResult BeginGetClientCertificate (AsyncCallback requestCallback, object state)
                {
-                       return null;
+                       if (gcc_delegate == null)
+                               gcc_delegate = new GCCDelegate (GetClientCertificate);
+                       return gcc_delegate.BeginInvoke (requestCallback, state);
                }
-#if SECURITY_DEP
+
                public X509Certificate2 EndGetClientCertificate (IAsyncResult asyncResult)
                {
-                       return null;
-                       // set no_client_certificate once done.
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+
+                       if (gcc_delegate == null)
+                               throw new InvalidOperationException ();
+
+                       return gcc_delegate.EndInvoke (asyncResult);
                }
 
                public X509Certificate2 GetClientCertificate ()
                {
-                       // set no_client_certificate once done.
+                       return context.Connection.ClientCertificate;
+               }
 
-                       // InvalidOp if call in progress.
-                       return null;
+#if NET_4_0
+               [MonoTODO]
+               public string ServiceName {
+                       get {
+                               return null;
+                       }
+               }
+               
+               public TransportContext TransportContext {
+                       get {
+                               return new Context ();
+                       }
+               }
+#endif
+               
+#if NET_4_5
+               public bool IsWebSocketRequest {
+                       get {
+                               string connection = headers.Get ("Connection");
+                               if (connection == null || ! connection.Equals ("upgrade", StringComparison.OrdinalIgnoreCase)) {
+                                       return false;
+                               }
+                               string upgrade = headers.Get ("Upgrade");
+                               if (upgrade == null || ! upgrade.Equals ("websocket", StringComparison.OrdinalIgnoreCase)) {
+                                       return false;
+                               }
+                               return true;
+                       }
+               }
+
+               public Task<X509Certificate2> GetClientCertificateAsync ()
+               {
+                       return Task<X509Certificate2>.Factory.FromAsync (BeginGetClientCertificate, EndGetClientCertificate, null);
                }
 #endif
        }