// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if SECURITY_DEP
-
-#if MONOTOUCH || MONODROID
-using Mono.Security.Protocol.Tls;
-#else
-extern alias MonoSecurity;
-using MonoSecurity::Mono.Security.Protocol.Tls;
-#endif
-
-#endif
-
using System.IO;
using System.Collections;
using System.Net.Sockets;
-using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Diagnostics;
-
using Mono.Net.Security;
namespace System.Net
NtlmAuthState connect_ntlm_auth_state;
HttpWebRequest connect_request;
- bool ssl;
- bool certsAvailable;
Exception connect_exception;
static object classLock = new object ();
- static Type sslStream;
-#if !MONOTOUCH && !MONODROID
- static PropertyInfo piClient;
- static PropertyInfo piServer;
- static PropertyInfo piTrustFailure;
-#endif
+ MonoTlsStream tlsStream;
-#if MONOTOUCH
+#if MONOTOUCH && !MONOTOUCH_TV && !MONOTOUCH_WATCH
[System.Runtime.InteropServices.DllImport ("__Internal")]
static extern void xamarin_start_wwan (string uri);
#endif
IPHostEntry hostEntry = sPoint.HostEntry;
if (hostEntry == null) {
-#if MONOTOUCH
+#if MONOTOUCH && !MONOTOUCH_TV && !MONOTOUCH_WATCH
xamarin_start_wwan (sPoint.Address.ToString ());
hostEntry = sPoint.HostEntry;
if (hostEntry == null) {
status = sPoint.UsesProxy ? WebExceptionStatus.ProxyNameResolutionFailure :
WebExceptionStatus.NameResolutionFailure;
return;
-#if MONOTOUCH
+#if MONOTOUCH && !MONOTOUCH_TV && !MONOTOUCH_WATCH
}
#endif
}
}
}
- static void EnsureSSLStreamAvailable ()
- {
- lock (classLock) {
- if (sslStream != null)
- return;
-
-#if NET_2_1 && SECURITY_DEP
- sslStream = typeof (HttpsClientStream);
-#else
- // HttpsClientStream is an internal glue class in Mono.Security.dll
- sslStream = Type.GetType ("Mono.Security.Protocol.Tls.HttpsClientStream, " +
- Consts.AssemblyMono_Security, false);
-
- if (sslStream == null) {
- string msg = "Missing Mono.Security.dll assembly. " +
- "Support for SSL/TLS is unavailable.";
-
- throw new NotSupportedException (msg);
- }
-#endif
-#if !MONOTOUCH && !MONODROID
- piClient = sslStream.GetProperty ("SelectedClientCertificate");
- piServer = sslStream.GetProperty ("ServerCertificate");
- piTrustFailure = sslStream.GetProperty ("TrustFailure");
-#endif
- }
- }
-
bool CreateTunnel (HttpWebRequest request, Uri connectUri,
Stream stream, out byte[] buffer)
{
NetworkStream serverStream = new NetworkStream (socket, false);
if (request.Address.Scheme == Uri.UriSchemeHttps) {
- ssl = true;
- EnsureSSLStreamAvailable ();
- if (!reused || nstream == null || nstream.GetType () != sslStream) {
+#if SECURITY_DEP
+ if (!reused || nstream == null || tlsStream == null) {
byte [] buffer = null;
if (sPoint.UseConnect) {
bool ok = CreateTunnel (request, sPoint.Address, serverStream, out buffer);
if (!ok)
return false;
}
-#if SECURITY_DEP
-#if MONOTOUCH || MONODROID
- nstream = new HttpsClientStream (serverStream, request.ClientCertificates, request, buffer);
-#else
- object[] args = new object [4] { serverStream,
- request.ClientCertificates,
- request, buffer};
- nstream = (Stream) Activator.CreateInstance (sslStream, args);
-#endif
- SslClientStream scs = (SslClientStream) nstream;
- var helper = new ChainValidationHelper (request);
- scs.ServerCertValidation2 += (certs) => helper.ValidateChain (request.Address.Host, certs);
-#endif
- certsAvailable = false;
+ tlsStream = new MonoTlsStream (request, serverStream);
+ nstream = tlsStream.CreateStream (buffer);
}
// we also need to set ServicePoint.Certificate
// and ServicePoint.ClientCertificate but this can
// only be done later (after handshake - which is
// done only after a read operation).
+#else
+ throw new NotSupportedException ();
+#endif
} else {
- ssl = false;
nstream = serverStream;
}
- } catch (Exception) {
- if (!request.Aborted)
+ } catch (Exception ex) {
+ if (tlsStream != null)
+ status = tlsStream.ExceptionStatus;
+ else if (!request.Aborted)
status = WebExceptionStatus.ConnectFailure;
return false;
}
return (statusCode >= 200 && statusCode != 204 && statusCode != 304);
}
- internal void GetCertificates (Stream stream)
- {
- // here the SSL negotiation have been done
-#if SECURITY_DEP && (MONOTOUCH || MONODROID)
- HttpsClientStream s = (stream as HttpsClientStream);
- X509Certificate client = s.SelectedClientCertificate;
- X509Certificate server = s.ServerCertificate;
-#else
- X509Certificate client = (X509Certificate) piClient.GetValue (stream, null);
- X509Certificate server = (X509Certificate) piServer.GetValue (stream, null);
-#endif
- sPoint.SetCertificates (client, server);
- certsAvailable = (server != null);
- }
-
internal static void InitRead (object state)
{
WebConnection cnc = (WebConnection) state;
return true;
}
- internal void ReadAsync (HttpWebRequest request, byte [] buffer, int offset, int size, WebAsyncResult result)
+
+ internal IAsyncResult BeginRead (HttpWebRequest request, byte [] buffer, int offset, int size, AsyncCallback cb, object state)
{
- bool error = false;
Stream s = null;
lock (this) {
if (Data.request != request)
- error = true;
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ return null;
s = nstream;
}
- if (error) {
- result.SetCompleted (true, new ObjectDisposedException (typeof(NetworkStream).FullName));
- result.DoCallback ();
- return;
- } else if (s == null) {
- result.SetCompleted (true);
- result.DoCallback ();
- return;
- }
-
- var data = new WebAsyncData (request, s, buffer, offset, size);
- ReadAsync (data, result);
- }
-
- void ReadAsync (WebAsyncData data, WebAsyncResult result)
- {
- bool running;
- try {
- running = ReadAsyncInner (data, result);
- } catch (Exception ex) {
- result.SetCompleted (true, ex);
- running = false;
+ IAsyncResult result = null;
+ if (!chunkedRead || (!chunkStream.DataAvailable && chunkStream.WantMore)) {
+ try {
+ result = s.BeginRead (buffer, offset, size, cb, state);
+ cb = null;
+ } catch (Exception) {
+ HandleError (WebExceptionStatus.ReceiveFailure, null, "chunked BeginRead");
+ throw;
+ }
}
- if (!running)
- result.DoCallback ();
- }
- bool ReadAsyncInner (WebAsyncData data, WebAsyncResult result)
- {
- if (chunkedRead && (chunkStream.DataAvailable || !chunkStream.WantMore)) {
- ReadAsyncInnerCB (data, result, null);
- return false;
+ if (chunkedRead) {
+ WebAsyncResult wr = new WebAsyncResult (cb, state, buffer, offset, size);
+ wr.InnerAsyncResult = result;
+ if (result == null) {
+ // Will be completed from the data in ChunkStream
+ wr.SetCompleted (true, (Exception) null);
+ wr.DoCallback ();
+ }
+ return wr;
}
- result.InnerAsyncResult = data.Stream.BeginRead (data.Buffer, data.Offset, data.Size, inner => ReadAsyncInnerCB (data, result, inner), null);
- return result.InnerAsyncResult != null && !result.InnerAsyncResult.CompletedSynchronously;
+ return result;
}
-
- bool ReadAsyncInnerCB (WebAsyncData data, WebAsyncResult result, IAsyncResult innerResult)
+
+ internal int EndRead (HttpWebRequest request, IAsyncResult result)
{
- var synch = innerResult != null ? innerResult.CompletedSynchronously : false;
-
- bool error = false;
Stream s = null;
lock (this) {
- if (Data.request != data.Request || nstream == null)
- error = true;
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
s = nstream;
}
- if (error) {
- result.SetCompleted (synch, new ObjectDisposedException (typeof(NetworkStream).FullName));
- result.DoCallback ();
- return false;
- }
-
int nbytes = 0;
- try {
- if (innerResult != null)
- nbytes = s.EndRead (innerResult);
- } catch (Exception ex) {
- result.SetCompleted (synch, ex);
- result.DoCallback ();
- return false;
- }
-
- var done = nbytes == 0;
-
- if (!chunkedRead) {
- result.SetCompleted (synch, nbytes);
- result.DoCallback ();
- return false;
+ bool done = false;
+ WebAsyncResult wr = null;
+ IAsyncResult nsAsync = ((WebAsyncResult) result).InnerAsyncResult;
+ if (chunkedRead && (nsAsync is WebAsyncResult)) {
+ wr = (WebAsyncResult) nsAsync;
+ IAsyncResult inner = wr.InnerAsyncResult;
+ if (inner != null && !(inner is WebAsyncResult)) {
+ nbytes = s.EndRead (inner);
+ done = nbytes == 0;
+ }
+ } else if (!(nsAsync is WebAsyncResult)) {
+ nbytes = s.EndRead (nsAsync);
+ wr = (WebAsyncResult) result;
+ done = nbytes == 0;
}
- try {
- chunkStream.WriteAndReadBack (data.Buffer, data.Offset, data.Size, ref nbytes);
- } catch (Exception e) {
- if (!(e is WebException))
- e = new WebException ("Invalid chunked data.", e, WebExceptionStatus.ServerProtocolViolation, null);
- result.SetCompleted (synch, e);
- result.DoCallback ();
- return false;
- }
+ if (chunkedRead) {
+ try {
+ chunkStream.WriteAndReadBack (wr.Buffer, wr.Offset, wr.Size, ref nbytes);
+ if (!done && nbytes == 0 && chunkStream.WantMore)
+ nbytes = EnsureRead (wr.Buffer, wr.Offset, wr.Size);
+ } catch (Exception e) {
+ if (e is WebException)
+ throw e;
- try {
- if (!done && nbytes == 0 && chunkStream.WantMore)
- return ReadAsyncInner (data, result);
- } catch (Exception e) {
- if (!(e is WebException))
- e = new WebException ("Invalid chunked data.", e, WebExceptionStatus.ServerProtocolViolation, null);
- result.SetCompleted (synch, e);
- result.DoCallback ();
- return false;
- }
+ throw new WebException ("Invalid chunked data.", e,
+ WebExceptionStatus.ServerProtocolViolation, null);
+ }
- if (done || nbytes == 0) {
- if (chunkStream.ChunkLeft != 0) {
- result.SetCompleted (synch, new WebException ("Read error", null, WebExceptionStatus.ConnectionClosed, null));
- result.DoCallback ();
- return false;
- } else if (chunkStream.WantMore) {
- result.SetCompleted (synch, new IOException ("Connection closed"));
- result.DoCallback ();
- return false;
+ if ((done || nbytes == 0) && chunkStream.ChunkLeft != 0) {
+ HandleError (WebExceptionStatus.ReceiveFailure, null, "chunked EndRead");
+ throw new WebException ("Read error", null, WebExceptionStatus.ReceiveFailure, null);
}
}
- result.SetCompleted (synch, nbytes);
- result.DoCallback ();
- return false;
+ return (nbytes != 0) ? nbytes : -1;
}
// To be called on chunkedRead when we can read no data from the ChunkStream yet
try {
s.Write (buffer, offset, size);
- // here SSL handshake should have been done
- if (ssl && !certsAvailable)
- GetCertificates (s);
} catch (Exception e) {
err_msg = e.Message;
WebExceptionStatus wes = WebExceptionStatus.SendFailure;
return false;
}
- // if SSL is in use then check for TrustFailure
- if (ssl) {
-#if SECURITY_DEP && (MONOTOUCH || MONODROID)
- HttpsClientStream https = (s as HttpsClientStream);
- if (https.TrustFailure) {
-#else
- if ((bool) piTrustFailure.GetValue (s , null)) {
-#endif
- wes = WebExceptionStatus.TrustFailure;
- msg = "Trust failure";
- }
- }
-
HandleError (wes, e, msg);
return false;
}