Connect()
        {
            Uri uri = CurrentRequest.HasProxy ? CurrentRequest.Proxy.Address : CurrentRequest.CurrentUri;

            if (Client == null)
                Client = new TcpClient();

            if (!Client.Connected)
            {
                Client.ConnectTimeout = CurrentRequest.ConnectTimeout;

//#if NETFX_CORE
                //await
//#endif
                string address = HTTPManager.GetHostCache (uri.Host);
                if (!string.IsNullOrEmpty (address)) {
                    Client.Connect (address, uri.Port);
                } else {
                    Client.Connect (uri.Host, uri.Port);
                    if (Client.IsConnected()) {
                        System.Net.IPEndPoint end_point = Client.Client.RemoteEndPoint as System.Net.IPEndPoint;
                        address = end_point.Address.ToString ();
                        HTTPManager.AddHostCache (uri.Host, address);
                    }
                }
                    
            } else {
//				NGUIDebug.print("Client.Connected ========>" + Client.Connected);
			}

            if (Stream == null)
            {
                if (HasProxy && !Proxy.IsTransparent)
                {
                    Stream = Client.GetStream();

                    var outStream = new BinaryWriter(Stream);
                    outStream.Write(string.Format("CONNECT {0}:{1} HTTP/1.1", CurrentRequest.CurrentUri.Host, CurrentRequest.CurrentUri.Port).GetASCIIBytes());
                    outStream.Write(HTTPRequest.EOL);
                    outStream.Write(string.Format("Host: {0}:{1}", CurrentRequest.CurrentUri.Host, CurrentRequest.CurrentUri.Port).GetASCIIBytes());
                    outStream.Write(HTTPRequest.EOL);
                    outStream.Write(string.Format("Proxy-Connection: Keep-Alive"));
                    outStream.Write(HTTPRequest.EOL);
                    outStream.Write(HTTPRequest.EOL);
                    outStream.Flush();
                    
                    ReadTo(Stream, HTTPResponse.LF);
                    ReadTo(Stream, HTTPResponse.LF);
                }
                
                if (HTTPProtocolFactory.IsSecureProtocol(uri))
                {
                    // On WP8 there are no Mono, so we must use the 'alternate' TlsHandlers
#if !UNITY_WP8 && !NETFX_CORE
                    if (CurrentRequest.UseAlternateSSL)
                    {
#endif
                        var handler = new TlsClientProtocol(Client.GetStream(), new Org.BouncyCastle.Security.SecureRandom());
                        handler.Connect(new LegacyTlsClient(new AlwaysValidVerifyer()));
                        Stream = handler.Stream;
#if !UNITY_WP8 && !NETFX_CORE
                    }
                    else
                    {
                        SslStream sslStream = new SslStream(Client.GetStream(), false, (sender, cert, chain, errors) =>
                        {
                            return CurrentRequest.CallCustomCertificationValidator(cert, chain);
                        });

                        if (!sslStream.IsAuthenticated)
                            sslStream.AuthenticateAsClient(uri.Host);
                        Stream = sslStream;
                    }
#endif
                }
                else
                    Stream = Client.GetStream();
            }
        }
Example #2
0
        public void Connect(Uri address)
        {
            IPAddress ip;

            if (address.HostNameType == UriHostNameType.Dns)
                ip = LookupDNS(address.Host);
            else
                ip = IPAddress.Parse(address.Host);

            if (ip == null)
                throw new HttpFetchException("No DNS for " + address.Host);

            //TODO: loop for all dns ips on connect failures

            var tcp = new TcpClient();
            var result = tcp.BeginConnect(ip, address.Port, null, null);
            if (!result.AsyncWaitHandle.WaitOne(ConnectTimeout, true))
            {
                tcp.Close();
                throw new HttpFetchException("Timeout connecting to " + ip);
            }
            tcp.EndConnect(result);
            socket = tcp.Client;
            stream = tcp.GetStream();

            if (address.Scheme == "https")
            {
                //Broken in mono with newer ciphers
                /*
                var ssl = new SslStream(stream, false, VerifyCert);
                ssl.AuthenticateAsClient(address.Host);
                stream = ssl;*/

                var handler = new TlsClientProtocol(stream, new SecureRandom());
                handler.Connect(new MyTlsClient(address.Host));
                stream = handler.Stream;
            }

            reader = new StreamLineReader(stream);
            Console.WriteLine("Connected to " + socket.RemoteEndPoint + "(" + address.Host + ")");
        }
        private void Connect()
        {
            Uri uri = CurrentRequest.HasProxy ? CurrentRequest.Proxy.Address : CurrentRequest.CurrentUri;

            #region TCP Connection

            if (Client == null)
                Client = new TcpClient();

            if (!Client.Connected)
            {
                Client.ConnectTimeout = CurrentRequest.ConnectTimeout;

#if NETFX_CORE
                Client.UseHTTPSProtocol = !CurrentRequest.UseAlternateSSL && HTTPProtocolFactory.IsSecureProtocol(uri);

                // On WinRT and >WP8 we use the more secure Tls12 protocol, but on WP8 only Ssl is available...
                #if UNITY_WP_8_1 || UNITY_METRO_8_1 || UNITY_METRO
                    Client.HTTPSProtocol = (int)SocketProtectionLevel.Tls12;
                #else
                    Client.HTTPSProtocol = (int)SocketProtectionLevel.Ssl;
                #endif
#endif

                Client.Connect(uri.Host, uri.Port);

                if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
                    HTTPManager.Logger.Information("HTTPConnection", "Connected to " + uri.Host + ":" + uri.Port.ToString());
            }
            else if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
                    HTTPManager.Logger.Information("HTTPConnection", "Already connected to " + uri.Host + ":" + uri.Port.ToString());

            #endregion

            lock (HTTPManager.Locker)
                StartTime = DateTime.UtcNow;

            if (Stream == null)
            {
                bool isSecure = HTTPProtocolFactory.IsSecureProtocol(CurrentRequest.CurrentUri);

                #region Proxy Handling

                if (HasProxy && (!Proxy.IsTransparent || (isSecure && Proxy.NonTransparentForHTTPS)))
                {
                    Stream = Client.GetStream();
                    var outStream = new BinaryWriter(Stream);

                    bool retry;
                    do
                    {
                        // If we have to becouse of a authentication request, we will switch it to true
                        retry = false;

                        outStream.SendAsASCII(string.Format("CONNECT {0}:{1} HTTP/1.1", CurrentRequest.CurrentUri.Host, CurrentRequest.CurrentUri.Port));
                        outStream.Write(HTTPRequest.EOL);

                        outStream.SendAsASCII("Proxy-Connection: Keep-Alive");
                        outStream.Write(HTTPRequest.EOL);

                        outStream.SendAsASCII("Connection: Keep-Alive");
                        outStream.Write(HTTPRequest.EOL);

                        outStream.SendAsASCII(string.Format("Host: {0}:{1}", CurrentRequest.CurrentUri.Host, CurrentRequest.CurrentUri.Port));
                        outStream.Write(HTTPRequest.EOL);

                        // Proxy Authentication
                        if (HasProxy && Proxy.Credentials != null)
                        {
                            switch (Proxy.Credentials.Type)
                            {
                                case AuthenticationTypes.Basic:
                                    // With Basic authentication we don't want to wait for a challange, we will send the hash with the first request
                                    outStream.Write(string.Format("Proxy-Authorization: {0}", string.Concat("Basic ", Convert.ToBase64String(Encoding.UTF8.GetBytes(Proxy.Credentials.UserName + ":" + Proxy.Credentials.Password)))).GetASCIIBytes());
                                    outStream.Write(HTTPRequest.EOL);
                                    break;

                                case AuthenticationTypes.Unknown:
                                case AuthenticationTypes.Digest:
                                    var digest = DigestStore.Get(Proxy.Address);
                                    if (digest != null)
                                    {
                                        string authentication = digest.GenerateResponseHeader(CurrentRequest, Proxy.Credentials);
                                        if (!string.IsNullOrEmpty(authentication))
                                        {
                                            outStream.Write(string.Format("Proxy-Authorization: {0}", authentication).GetASCIIBytes());
                                            outStream.Write(HTTPRequest.EOL);
                                        }
                                    }

                                    break;
                            }
                        }

                        outStream.Write(HTTPRequest.EOL);

                        // Make sure to send all the wrote data to the wire
                        outStream.Flush();
                        
                        CurrentRequest.ProxyResponse = new HTTPResponse(CurrentRequest, Stream, false, false);

                        // Read back the response of the proxy
                        if (!CurrentRequest.ProxyResponse.Receive(-1, true))
                            throw new Exception("Connection to the Proxy Server failed!");

                        if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
                            HTTPManager.Logger.Information("HTTPConnection", "Proxy returned - status code: " + CurrentRequest.ProxyResponse.StatusCode + " message: " + CurrentRequest.ProxyResponse.Message);

                        switch(CurrentRequest.ProxyResponse.StatusCode)
                        {
                            // Proxy authentication required
                            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.8
                            case 407:
                            {
                                string authHeader = DigestStore.FindBest(CurrentRequest.ProxyResponse.GetHeaderValues("proxy-authenticate"));
                                if (!string.IsNullOrEmpty(authHeader))
                                {
                                    var digest = DigestStore.GetOrCreate(Proxy.Address);
                                    digest.ParseChallange(authHeader);

                                    if (Proxy.Credentials != null && digest.IsUriProtected(Proxy.Address) && (!CurrentRequest.HasHeader("Proxy-Authorization") || digest.Stale))
                                        retry = true;
                                }
                                break;
                            }

                            default:
                                if (!CurrentRequest.ProxyResponse.IsSuccess)
                                    throw new Exception(string.Format("Proxy returned Status Code: \"{0}\", Message: \"{1}\" and Response: {2}", CurrentRequest.ProxyResponse.StatusCode, CurrentRequest.ProxyResponse.Message, CurrentRequest.ProxyResponse.DataAsText));
                                break;
                        }

                    } while (retry);
                }

                #endregion

                // We have to use CurrentRequest.CurrentUri here, becouse uri can be a proxy uri with a different protocol
                if (isSecure)
                {
                    #region SSL Upgrade

                    // On WP8 there are no Mono, so we must use the 'alternate' TlsHandlers
                    if (CurrentRequest.UseAlternateSSL)
                    {
                        var handler = new TlsClientProtocol(Client.GetStream(), new Org.BouncyCastle.Security.SecureRandom());

                        // http://tools.ietf.org/html/rfc3546#section-3.1
                        // It is RECOMMENDED that clients include an extension of type "server_name" in the client hello whenever they locate a server by a supported name type.
                        List<string> hostNames = new List<string>(1);
                        hostNames.Add(CurrentRequest.CurrentUri.Host);

                        handler.Connect(new LegacyTlsClient(CurrentRequest.CurrentUri,
                                                            CurrentRequest.CustomCertificateVerifyer == null ? new AlwaysValidVerifyer() : CurrentRequest.CustomCertificateVerifyer, 
                                                            null, 
                                                            hostNames));

                        Stream = handler.Stream;
                    }
                    else
                    {
#if !UNITY_WP8 && !NETFX_CORE
                        SslStream sslStream = new SslStream(Client.GetStream(), false, (sender, cert, chain, errors) =>
                        {
                            return CurrentRequest.CallCustomCertificationValidator(cert, chain);
                        });

                        if (!sslStream.IsAuthenticated)
                            sslStream.AuthenticateAsClient(CurrentRequest.CurrentUri.Host);
                        Stream = sslStream;
#else
                        Stream = Client.GetStream();
#endif
                    }

                    #endregion
                }
                else
                    Stream = Client.GetStream();
            }
        }