private void Connect() { Uri uri = #if !BESTHTTP_DISABLE_PROXY CurrentRequest.HasProxy ? CurrentRequest.Proxy.Address : #endif CurrentRequest.CurrentUri; #region TCP Connection if (Client == null) { Client = new TcpClient(); } if (!Client.Connected) { Client.ConnectTimeout = CurrentRequest.ConnectTimeout; #if NETFX_CORE || (UNITY_WP8 && !UNITY_EDITOR) Client.UseHTTPSProtocol = #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) !CurrentRequest.UseAlternateSSL && #endif HTTPProtocolFactory.IsSecureProtocol(uri); #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); #if !BESTHTTP_DISABLE_PROXY #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 #endif // #if !BESTHTTP_DISABLE_PROXY // We have to use CurrentRequest.CurrentUri here, becouse uri can be a proxy uri with a different protocol if (isSecure) { #region SSL Upgrade #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) 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, CurrentRequest.CustomClientCredentialsProvider, hostNames)); Stream = handler.Stream; } else #endif { #if !NETFX_CORE && !UNITY_WP8 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(); } } }
void ThreadFunc(object param) { bool alreadyReconnected = false; bool redirected = false; RetryCauses cause = RetryCauses.None; #if LOCK_ON_FILE object uriLock = null; #endif #if UNITY_WEBPLAYER // Right now, no caching supported in the webplayer if (!CurrentRequest.DisableCache) { CurrentRequest.DisableCache = true; } #endif try { if (!HasProxy && CurrentRequest.HasProxy) { Proxy = CurrentRequest.Proxy; } // Lock only if we will use the cached entity. #if LOCK_ON_FILE if (!CurrentRequest.DisableCache) { Monitor.Enter(uriLock = HTTPCacheFileLock.Acquire(CurrentRequest.CurrentUri)); } #endif // Try load the full response from an already saved cache entity. If the response if (TryLoadAllFromCache()) { return; } if (Client != null && !Client.IsConnected()) { Close(); } do // of while (reconnect) { if (cause == RetryCauses.Reconnect) { Close(); #if NETFX_CORE await Task.Delay(100); #else Thread.Sleep(100); #endif } LastProcessedUri = CurrentRequest.CurrentUri; cause = RetryCauses.None; // Connect to the server Connect(); if (State == HTTPConnectionStates.AbortRequested) { throw new Exception("AbortRequested"); } // Setup cache control headers before we send out the request if (!CurrentRequest.DisableCache) { HTTPCacheService.SetHeaders(CurrentRequest); } // Write the request to the stream // sentRequest will be true if the request sent out successfully(no SocketException), so we can try read the response bool sentRequest = CurrentRequest.SendOutTo(Stream); // sentRequest only true if there are no exceptions during CurrentRequest.SendOutTo. if (!sentRequest) { Close(); if (State == HTTPConnectionStates.TimedOut) { throw new Exception("AbortRequested"); } // We will try again only once if (!alreadyReconnected) { alreadyReconnected = true; cause = RetryCauses.Reconnect; } } // If sending out the request succeded, we will try read the response. if (sentRequest) { bool received = Receive(); if (State == HTTPConnectionStates.TimedOut) { throw new Exception("AbortRequested"); } if (!received && !alreadyReconnected) { alreadyReconnected = true; cause = RetryCauses.Reconnect; } if (CurrentRequest.Response != null) { switch (CurrentRequest.Response.StatusCode) { // Not authorized // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2 case 401: { string authHeader = CurrentRequest.Response.GetFirstHeaderValue("www-authenticate"); if (!string.IsNullOrEmpty(authHeader)) { var digest = DigestStore.GetOrCreate(CurrentRequest.CurrentUri); digest.ParseChallange(authHeader); if (CurrentRequest.Credentials != null && digest.IsUriProtected(CurrentRequest.CurrentUri) && (!CurrentRequest.HasHeader("Authorization") || digest.Stale)) { cause = RetryCauses.Authenticate; } } goto default; } // Proxy authentication required // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.8 case 407: { if (CurrentRequest.HasProxy) { string authHeader = CurrentRequest.Response.GetFirstHeaderValue("proxy-authenticate"); if (!string.IsNullOrEmpty(authHeader)) { var digest = DigestStore.GetOrCreate(CurrentRequest.Proxy.Address); digest.ParseChallange(authHeader); if (CurrentRequest.Proxy.Credentials != null && digest.IsUriProtected(CurrentRequest.Proxy.Address) && (!CurrentRequest.HasHeader("Proxy-Authorization") || digest.Stale)) { cause = RetryCauses.ProxyAuthenticate; } } } goto default; } // Redirected case 301: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2 case 302: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3 case 307: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.8 case 308: // http://tools.ietf.org/html/rfc7238 { if (CurrentRequest.RedirectCount >= CurrentRequest.MaxRedirects) { goto default; } CurrentRequest.RedirectCount++; string location = CurrentRequest.Response.GetFirstHeaderValue("location"); if (!string.IsNullOrEmpty(location)) { Uri redirectUri = GetRedirectUri(location); // Let the user to take some control over the redirection if (!CurrentRequest.CallOnBeforeRedirection(redirectUri)) { HTTPManager.Logger.Information("HTTPConnection", "OnBeforeRedirection returned False"); goto default; } // Remove the previously set Host header. CurrentRequest.RemoveHeader("Host"); // Set the Referer header to the last Uri. CurrentRequest.SetHeader("Referer", CurrentRequest.CurrentUri.ToString()); // Set the new Uri, the CurrentUri will return this while the IsRedirected property is true CurrentRequest.RedirectUri = redirectUri; // Discard the redirect response, we don't need it any more CurrentRequest.Response = null; redirected = CurrentRequest.IsRedirected = true; } else #if !NETFX_CORE { throw new MissingFieldException(string.Format("Got redirect status({0}) without 'location' header!", CurrentRequest.Response.StatusCode.ToString())); } #else { throw new Exception(string.Format("Got redirect status({0}) without 'location' header!", CurrentRequest.Response.StatusCode.ToString())); } #endif goto default; } default: if (CurrentRequest.IsCookiesEnabled) { CookieJar.Set(CurrentRequest.Response); } TryStoreInCache(); break; } // If we have a response and the server telling us that it closed the connection after the message sent to us, then // we will colse the connection too. if (CurrentRequest.Response == null || CurrentRequest.Response.HasHeaderWithValue("connection", "close") || CurrentRequest.UseAlternateSSL) { Close(); } } } } while (cause != RetryCauses.None); } catch (TimeoutException e) { CurrentRequest.Response = null; CurrentRequest.Exception = e; CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut; Close(); } catch (Exception e) { if (CurrentRequest.UseStreaming) { HTTPCacheService.DeleteEntity(CurrentRequest.CurrentUri); } // Something gone bad, Response must be null! CurrentRequest.Response = null; switch (State) { case HTTPConnectionStates.AbortRequested: CurrentRequest.State = HTTPRequestStates.Aborted; break; case HTTPConnectionStates.TimedOut: CurrentRequest.State = HTTPRequestStates.TimedOut; break; default: CurrentRequest.Exception = e; CurrentRequest.State = HTTPRequestStates.Error; break; } Close(); } finally { #if LOCK_ON_FILE if (!CurrentRequest.DisableCache && uriLock != null) { Monitor.Exit(uriLock); } #endif // Avoid state changes. While we are in this block changing the connection's State, on Unity's main thread // the HTTPManager's OnUpdate will check the connections's State and call functions that can change the inner state of // the object. (Like setting the CurrentRequest to null in function Recycle() causing a NullRef exception) lock (HTTPManager.Locker) { if (CurrentRequest != null && CurrentRequest.Response != null && CurrentRequest.Response.IsUpgraded) { State = HTTPConnectionStates.Upgraded; } else { State = redirected ? HTTPConnectionStates.Redirected : (Client == null ? HTTPConnectionStates.Closed : HTTPConnectionStates.WaitForRecycle); } // Change the request's state only when the whole processing finished if (CurrentRequest.State == HTTPRequestStates.Processing && (State == HTTPConnectionStates.Closed || State == HTTPConnectionStates.WaitForRecycle)) { CurrentRequest.State = HTTPRequestStates.Finished; } if (CurrentRequest.State == HTTPRequestStates.ConnectionTimedOut) { State = HTTPConnectionStates.Closed; } LastProcessTime = DateTime.UtcNow; } HTTPCacheService.SaveLibrary(); CookieJar.Persist(); } }
internal override void Connect(Stream stream, HTTPRequest request) { bool isSecure = HTTPProtocolFactory.IsSecureProtocol(request.CurrentUri); if ((!this.IsTransparent || (isSecure && this.NonTransparentForHTTPS))) { using (var bufferedStream = new WriteOnlyBufferedStream(stream, HTTPRequest.UploadChunkSize)) using (var outStream = new BinaryWriter(bufferedStream, Encoding.UTF8)) { bool retry; do { // If we have to because of a authentication request, we will switch it to true retry = false; string connectStr = string.Format("CONNECT {0}:{1} HTTP/1.1", request.CurrentUri.Host, request.CurrentUri.Port.ToString()); HTTPManager.Logger.Information("HTTPConnection", "Sending " + connectStr); outStream.SendAsASCII(connectStr); 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}", request.CurrentUri.Host, request.CurrentUri.Port.ToString())); outStream.Write(HTTPRequest.EOL); // Proxy Authentication if (this.Credentials != null) { switch (this.Credentials.Type) { case AuthenticationTypes.Basic: // With Basic authentication we don't want to wait for a challenge, we will send the hash with the first request outStream.Write(string.Format("Proxy-Authorization: {0}", string.Concat("Basic ", Convert.ToBase64String(Encoding.UTF8.GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)))).GetASCIIBytes()); outStream.Write(HTTPRequest.EOL); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: var digest = DigestStore.Get(this.Address); if (digest != null) { string authentication = digest.GenerateResponseHeader(request, this.Credentials, true); if (!string.IsNullOrEmpty(authentication)) { string auth = string.Format("Proxy-Authorization: {0}", authentication); if (HTTPManager.Logger.Level <= Logger.Loglevels.Information) { HTTPManager.Logger.Information("HTTPConnection", "Sending proxy authorization header: " + auth); } var bytes = auth.GetASCIIBytes(); outStream.Write(bytes); outStream.Write(HTTPRequest.EOL); VariableSizedBufferPool.Release(bytes); } } break; } } outStream.Write(HTTPRequest.EOL); // Make sure to send all the wrote data to the wire outStream.Flush(); request.ProxyResponse = new HTTPResponse(request, stream, false, false); // Read back the response of the proxy if (!request.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: " + request.ProxyResponse.StatusCode + " message: " + request.ProxyResponse.Message + " Body: " + request.ProxyResponse.DataAsText); } switch (request.ProxyResponse.StatusCode) { // Proxy authentication required // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.8 case 407: { string authHeader = DigestStore.FindBest(request.ProxyResponse.GetHeaderValues("proxy-authenticate")); if (!string.IsNullOrEmpty(authHeader)) { var digest = DigestStore.GetOrCreate(this.Address); digest.ParseChallange(authHeader); if (this.Credentials != null && digest.IsUriProtected(this.Address) && (!request.HasHeader("Proxy-Authorization") || digest.Stale)) { retry = true; } } if (!retry) { throw new Exception(string.Format("Can't authenticate Proxy! Status Code: \"{0}\", Message: \"{1}\" and Response: {2}", request.ProxyResponse.StatusCode, request.ProxyResponse.Message, request.ProxyResponse.DataAsText)); } break; } default: if (!request.ProxyResponse.IsSuccess) { throw new Exception(string.Format("Proxy returned Status Code: \"{0}\", Message: \"{1}\" and Response: {2}", request.ProxyResponse.StatusCode, request.ProxyResponse.Message, request.ProxyResponse.DataAsText)); } break; } } while (retry); }// using outstream } }
void ThreadFunc(object param) { bool alreadyReconnected = false; bool redirected = false; RetryCauses cause = RetryCauses.None; try { #if !BESTHTTP_DISABLE_PROXY if (!HasProxy && CurrentRequest.HasProxy) { Proxy = CurrentRequest.Proxy; } #endif #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR) // Try load the full response from an already saved cache entity. If the response if (TryLoadAllFromCache()) { return; } #endif if (Client != null && !Client.IsConnected()) { Close(); } do // of while (reconnect) { if (cause == RetryCauses.Reconnect) { Close(); #if NETFX_CORE await Task.Delay(100); #else Thread.Sleep(100); #endif } LastProcessedUri = CurrentRequest.CurrentUri; cause = RetryCauses.None; // Connect to the server Connect(); if (State == HTTPConnectionStates.AbortRequested) { throw new Exception("AbortRequested"); } #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR) // Setup cache control headers before we send out the request if (!CurrentRequest.DisableCache) { HTTPCacheService.SetHeaders(CurrentRequest); } #endif // Write the request to the stream // sentRequest will be true if the request sent out successfully(no SocketException), so we can try read the response bool sentRequest = false; try { #if !NETFX_CORE Client.NoDelay = CurrentRequest.TryToMinimizeTCPLatency; #endif CurrentRequest.SendOutTo(Stream); sentRequest = true; } catch (Exception ex) { Close(); if (State == HTTPConnectionStates.TimedOut || State == HTTPConnectionStates.AbortRequested) { throw new Exception("AbortRequested"); } // We will try again only once if (!alreadyReconnected && !CurrentRequest.DisableRetry) { alreadyReconnected = true; cause = RetryCauses.Reconnect; } else // rethrow exception { throw ex; } } // If sending out the request succeeded, we will try read the response. if (sentRequest) { bool received = Receive(); if (State == HTTPConnectionStates.TimedOut || State == HTTPConnectionStates.AbortRequested) { throw new Exception("AbortRequested"); } if (!received && !alreadyReconnected && !CurrentRequest.DisableRetry) { alreadyReconnected = true; cause = RetryCauses.Reconnect; } if (CurrentRequest.Response != null) { #if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR) // Try to store cookies before we do anything else, as we may remove the response deleting the cookies as well. if (CurrentRequest.IsCookiesEnabled) { CookieJar.Set(CurrentRequest.Response); } #endif switch (CurrentRequest.Response.StatusCode) { // Not authorized // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2 case 401: { string authHeader = DigestStore.FindBest(CurrentRequest.Response.GetHeaderValues("www-authenticate")); if (!string.IsNullOrEmpty(authHeader)) { var digest = DigestStore.GetOrCreate(CurrentRequest.CurrentUri); digest.ParseChallange(authHeader); if (CurrentRequest.Credentials != null && digest.IsUriProtected(CurrentRequest.CurrentUri) && (!CurrentRequest.HasHeader("Authorization") || digest.Stale)) { cause = RetryCauses.Authenticate; } } goto default; } #if !BESTHTTP_DISABLE_PROXY // Proxy authentication required // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.8 case 407: { if (CurrentRequest.HasProxy) { string authHeader = DigestStore.FindBest(CurrentRequest.Response.GetHeaderValues("proxy-authenticate")); if (!string.IsNullOrEmpty(authHeader)) { var digest = DigestStore.GetOrCreate(CurrentRequest.Proxy.Address); digest.ParseChallange(authHeader); if (CurrentRequest.Proxy.Credentials != null && digest.IsUriProtected(CurrentRequest.Proxy.Address) && (!CurrentRequest.HasHeader("Proxy-Authorization") || digest.Stale)) { cause = RetryCauses.ProxyAuthenticate; } } } goto default; } #endif // Redirected case 301: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2 case 302: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3 case 307: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.8 case 308: // http://tools.ietf.org/html/rfc7238 { if (CurrentRequest.RedirectCount >= CurrentRequest.MaxRedirects) { goto default; } CurrentRequest.RedirectCount++; string location = CurrentRequest.Response.GetFirstHeaderValue("location"); if (!string.IsNullOrEmpty(location)) { Uri redirectUri = GetRedirectUri(location); if (HTTPManager.Logger.Level == Logger.Loglevels.All) { HTTPManager.Logger.Verbose("HTTPConnection", string.Format("{0} - Redirected to Location: '{1}' redirectUri: '{1}'", this.CurrentRequest.CurrentUri.ToString(), location, redirectUri)); } // Let the user to take some control over the redirection if (!CurrentRequest.CallOnBeforeRedirection(redirectUri)) { HTTPManager.Logger.Information("HTTPConnection", "OnBeforeRedirection returned False"); goto default; } // Remove the previously set Host header. CurrentRequest.RemoveHeader("Host"); // Set the Referer header to the last Uri. CurrentRequest.SetHeader("Referer", CurrentRequest.CurrentUri.ToString()); // Set the new Uri, the CurrentUri will return this while the IsRedirected property is true CurrentRequest.RedirectUri = redirectUri; // Discard the redirect response, we don't need it any more CurrentRequest.Response = null; redirected = CurrentRequest.IsRedirected = true; } else #if !NETFX_CORE { throw new MissingFieldException(string.Format("Got redirect status({0}) without 'location' header!", CurrentRequest.Response.StatusCode.ToString())); } #else { throw new Exception(string.Format("Got redirect status({0}) without 'location' header!", CurrentRequest.Response.StatusCode.ToString())); } #endif goto default; } default: #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR) TryStoreInCache(); #endif break; } // If we have a response and the server telling us that it closed the connection after the message sent to us, then // we will close the connection too. bool closeByServer = CurrentRequest.Response == null || CurrentRequest.Response.HasHeaderWithValue("connection", "close"); bool closeByClient = !CurrentRequest.Response.IsClosedManually && !CurrentRequest.IsKeepAlive; if (closeByServer || closeByClient) { Close(); } else if (CurrentRequest.Response != null) { var keepAliveheaderValues = CurrentRequest.Response.GetHeaderValues("keep-alive"); if (keepAliveheaderValues != null && keepAliveheaderValues.Count > 0) { if (KeepAlive == null) { KeepAlive = new KeepAliveHeader(); } KeepAlive.Parse(keepAliveheaderValues); } } } } } while (cause != RetryCauses.None); } catch (TimeoutException e) { CurrentRequest.Response = null; CurrentRequest.Exception = e; CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut; Close(); } catch (Exception e) { if (CurrentRequest != null) { #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR) if (CurrentRequest.UseStreaming) { HTTPCacheService.DeleteEntity(CurrentRequest.CurrentUri); } #endif // Something gone bad, Response must be null! CurrentRequest.Response = null; switch (State) { case HTTPConnectionStates.Closed: case HTTPConnectionStates.AbortRequested: CurrentRequest.State = HTTPRequestStates.Aborted; break; case HTTPConnectionStates.TimedOut: CurrentRequest.State = HTTPRequestStates.TimedOut; break; default: CurrentRequest.Exception = e; CurrentRequest.State = HTTPRequestStates.Error; break; } } Close(); } finally { if (CurrentRequest != null) { // Avoid state changes. While we are in this block changing the connection's State, on Unity's main thread // the HTTPManager's OnUpdate will check the connections's State and call functions that can change the inner state of // the object. (Like setting the CurrentRequest to null in function Recycle() causing a NullRef exception) lock (HTTPManager.Locker) { if (CurrentRequest != null && CurrentRequest.Response != null && CurrentRequest.Response.IsUpgraded) { State = HTTPConnectionStates.Upgraded; } else { State = redirected ? HTTPConnectionStates.Redirected : (Client == null ? HTTPConnectionStates.Closed : HTTPConnectionStates.WaitForRecycle); } // Change the request's state only when the whole processing finished if (CurrentRequest.State == HTTPRequestStates.Processing && (State == HTTPConnectionStates.Closed || State == HTTPConnectionStates.WaitForRecycle)) { if (CurrentRequest.Response != null) { CurrentRequest.State = HTTPRequestStates.Finished; } else { CurrentRequest.Exception = new Exception(string.Format("Remote server closed the connection before sending response header! Previous request state: {0}. Connection state: {1}", CurrentRequest.State.ToString(), State.ToString())); CurrentRequest.State = HTTPRequestStates.Error; } } if (CurrentRequest.State == HTTPRequestStates.ConnectionTimedOut) { State = HTTPConnectionStates.Closed; } LastProcessTime = DateTime.UtcNow; if (OnConnectionRecycled != null) { RecycleNow(); } } #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR) HTTPCacheService.SaveLibrary(); #endif #if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR) CookieJar.Persist(); #endif } } }
private void ThreadFunc(object param) { bool flag = false; bool flag2 = false; RetryCauses retryCauses = RetryCauses.None; object obj = null; try { if (!CurrentRequest.DisableCache) { Monitor.Enter(obj = HTTPCacheFileLock.Acquire(CurrentRequest.CurrentUri)); } CurrentRequest.Processing = true; if (!TryLoadAllFromCache()) { if (Client != null && !Client.IsConnected()) { Close(); } do { if (retryCauses == RetryCauses.Reconnect) { Close(); Thread.Sleep(100); } retryCauses = RetryCauses.None; Connect(); if (!CurrentRequest.DisableCache) { HTTPCacheService.SetHeaders(CurrentRequest); } bool flag3 = CurrentRequest.SendOutTo(Stream); if (!flag3) { Close(); if (!flag) { flag = true; retryCauses = RetryCauses.Reconnect; } } if (flag3) { if (!Receive() && !flag) { flag = true; retryCauses = RetryCauses.Reconnect; } if (CurrentRequest.Response != null) { switch (CurrentRequest.Response.StatusCode) { case 401: { string firstHeaderValue2 = CurrentRequest.Response.GetFirstHeaderValue("www-authenticate"); if (!string.IsNullOrEmpty(firstHeaderValue2)) { Digest orCreate = DigestStore.GetOrCreate(CurrentRequest.CurrentUri); orCreate.ParseChallange(firstHeaderValue2); if (CurrentRequest.Credentials != null && orCreate.IsUriProtected(CurrentRequest.CurrentUri) && (!CurrentRequest.HasHeader("Authorization") || orCreate.Stale)) { retryCauses = RetryCauses.Authenticate; } } break; } case 301: case 302: case 307: if (CurrentRequest.RedirectCount < CurrentRequest.MaxRedirects) { CurrentRequest.RedirectCount++; string firstHeaderValue = CurrentRequest.Response.GetFirstHeaderValue("location"); if (string.IsNullOrEmpty(firstHeaderValue)) { throw new MissingFieldException($"Got redirect status({CurrentRequest.Response.StatusCode.ToString()}) without 'location' header!"); } CurrentRequest.RedirectUri = GetRedirectUri(firstHeaderValue); CurrentRequest.Response = null; bool flag4 = true; CurrentRequest.IsRedirected = flag4; flag2 = flag4; } break; } TryStoreInCache(); if (CurrentRequest.Response.HasHeaderWithValue("connection", "close") || CurrentRequest.UseAlternateSSL) { Close(); } } } }while (retryCauses != 0); } } catch (Exception exception) { if (CurrentRequest.UseStreaming) { HTTPCacheService.DeleteEntity(CurrentRequest.CurrentUri); } CurrentRequest.Response = null; CurrentRequest.Exception = exception; Close(); } finally { if (!CurrentRequest.DisableCache && obj != null) { Monitor.Exit(obj); } HTTPCacheService.SaveLibrary(); CurrentRequest.Processing = false; if (CurrentRequest != null && CurrentRequest.Response != null && CurrentRequest.Response.IsUpgraded) { State = HTTPConnectionStates.Upgraded; } else { State = (flag2 ? HTTPConnectionStates.Redirected : ((Client != null) ? HTTPConnectionStates.WaitForRecycle : HTTPConnectionStates.Closed)); } LastProcessTime = DateTime.UtcNow; } }
public static void HandleResponse(string context, HTTPRequest request, out bool resendRequest, out HTTPConnectionStates proposedConnectionState, ref KeepAliveHeader keepAlive) { resendRequest = false; proposedConnectionState = HTTPConnectionStates.Processing; if (request.Response != null) { #if !BESTHTTP_DISABLE_COOKIES // Try to store cookies before we do anything else, as we may remove the response deleting the cookies as well. if (request.IsCookiesEnabled && CookieJar.Set(request.Response)) { PluginEventHelper.EnqueuePluginEvent(new PluginEventInfo(PluginEvents.SaveCookieLibrary)); } #endif switch (request.Response.StatusCode) { // Not authorized // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2 case 401: { string authHeader = DigestStore.FindBest(request.Response.GetHeaderValues("www-authenticate")); if (!string.IsNullOrEmpty(authHeader)) { var digest = DigestStore.GetOrCreate(request.CurrentUri); digest.ParseChallange(authHeader); if (request.Credentials != null && digest.IsUriProtected(request.CurrentUri) && (!request.HasHeader("Authorization") || digest.Stale)) { resendRequest = true; } } goto default; } // Redirected case 301: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2 case 302: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3 case 307: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.8 case 308: // http://tools.ietf.org/html/rfc7238 { if (request.RedirectCount >= request.MaxRedirects) { goto default; } request.RedirectCount++; string location = request.Response.GetFirstHeaderValue("location"); if (!string.IsNullOrEmpty(location)) { Uri redirectUri = ConnectionHelper.GetRedirectUri(request, location); if (HTTPManager.Logger.Level == Logger.Loglevels.All) { HTTPManager.Logger.Verbose("HTTPConnection", string.Format("[{0}] - Redirected to Location: '{1}' redirectUri: '{1}'", context, location, redirectUri)); } // Let the user to take some control over the redirection if (!request.CallOnBeforeRedirection(redirectUri)) { HTTPManager.Logger.Information("HTTPConnection", string.Format("[{0}] OnBeforeRedirection returned False", context)); goto default; } // Remove the previously set Host header. request.RemoveHeader("Host"); // Set the Referer header to the last Uri. request.SetHeader("Referer", request.CurrentUri.ToString()); // Set the new Uri, the CurrentUri will return this while the IsRedirected property is true request.RedirectUri = redirectUri; // Discard the redirect response, we don't need it any more request.Response = null; request.IsRedirected = true; resendRequest = true; } else { throw new Exception(string.Format("[{0}] Got redirect status({1}) without 'location' header!", context, request.Response.StatusCode.ToString())); } goto default; } #if !BESTHTTP_DISABLE_CACHING case 304: if (request.DisableCache) { break; } if (ConnectionHelper.LoadFromCache(context, request)) { HTTPManager.Logger.Verbose("HTTPConnection", string.Format("[{0}] - HandleResponse - Loaded from cache successfully!", context)); } else { HTTPManager.Logger.Verbose("HTTPConnection", string.Format("[{0}] - HandleResponse - Loaded from cache failed!", context)); resendRequest = true; } break; #endif default: #if !BESTHTTP_DISABLE_CACHING ConnectionHelper.TryStoreInCache(request); #endif break; } // Closing the stream is done manually? if (!request.Response.IsClosedManually) { // If we have a response and the server telling us that it closed the connection after the message sent to us, then // we will close the connection too. bool closeByServer = request.Response.HasHeaderWithValue("connection", "close"); bool closeByClient = !request.IsKeepAlive; if (closeByServer || closeByClient) { proposedConnectionState = HTTPConnectionStates.Closed; } else if (request.Response != null) { var keepAliveheaderValues = request.Response.GetHeaderValues("keep-alive"); if (keepAliveheaderValues != null && keepAliveheaderValues.Count > 0) { if (keepAlive == null) { keepAlive = new KeepAliveHeader(); } keepAlive.Parse(keepAliveheaderValues); } } } } }
public void EnumerateHeaders(OnHeaderEnumerationDelegate callback) { if (!HasHeader("Host")) { SetHeader("Host", CurrentUri.Authority); } if (IsRedirected && !HasHeader("Referer")) { AddHeader("Referer", Uri.ToString()); } if (!HasHeader("Accept-Encoding")) { AddHeader("Accept-Encoding", "gzip, identity"); } if (HasProxy && !HasHeader("Proxy-Connection")) { AddHeader("Proxy-Connection", (!IsKeepAlive) ? "Close" : "Keep-Alive"); } if (!HasHeader("Connection")) { AddHeader("Connection", (!IsKeepAlive) ? "Close, TE" : "Keep-Alive, TE"); } if (!HasHeader("TE")) { AddHeader("TE", "identity"); } if (!HasHeader("User-Agent")) { AddHeader("User-Agent", "VRC.Core.BestHTTP"); } long num = -1L; if (UploadStream == null) { byte[] entityBody = GetEntityBody(); num = ((entityBody != null) ? entityBody.Length : 0); if (RawData == null && (FormImpl != null || (FieldCollector != null && !FieldCollector.IsEmpty))) { SelectFormImplementation(); if (FormImpl != null) { FormImpl.PrepareRequest(this); } } } else { num = UploadStreamLength; if (num == -1) { SetHeader("Transfer-Encoding", "Chunked"); } if (!HasHeader("Content-Type")) { SetHeader("Content-Type", "application/octet-stream"); } } if (num != -1 && !HasHeader("Content-Length")) { SetHeader("Content-Length", num.ToString()); } if (HasProxy && Proxy.Credentials != null) { switch (Proxy.Credentials.Type) { case AuthenticationTypes.Basic: SetHeader("Proxy-Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Proxy.Credentials.UserName + ":" + Proxy.Credentials.Password))); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest = DigestStore.Get(Proxy.Address); if (digest != null) { string value = digest.GenerateResponseHeader(this, Proxy.Credentials); if (!string.IsNullOrEmpty(value)) { SetHeader("Proxy-Authorization", value); } } break; } } } if (Credentials != null) { switch (Credentials.Type) { case AuthenticationTypes.Basic: SetHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Credentials.UserName + ":" + Credentials.Password))); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest2 = DigestStore.Get(CurrentUri); if (digest2 != null) { string value2 = digest2.GenerateResponseHeader(this, Credentials); if (!string.IsNullOrEmpty(value2)) { SetHeader("Authorization", value2); } } break; } } } List <Cookie> list = (!IsCookiesEnabled) ? null : CookieJar.Get(CurrentUri); if (list == null || list.Count == 0) { list = customCookies; } else if (customCookies != null) { for (int i = 0; i < customCookies.Count; i++) { Cookie customCookie = customCookies[i]; int num2 = list.FindIndex((Cookie c) => c.Name.Equals(customCookie.Name)); if (num2 >= 0) { list[num2] = customCookie; } else { list.Add(customCookie); } } } if (list != null && list.Count > 0) { bool flag = true; string text = string.Empty; bool flag2 = HTTPProtocolFactory.IsSecureProtocol(CurrentUri); SupportedProtocols protocolFromUri = HTTPProtocolFactory.GetProtocolFromUri(CurrentUri); foreach (Cookie item in list) { if ((!item.IsSecure || (item.IsSecure && flag2)) && (!item.IsHttpOnly || (item.IsHttpOnly && protocolFromUri == SupportedProtocols.HTTP))) { if (!flag) { text += "; "; } else { flag = false; } text += item.ToString(); item.LastAccess = DateTime.UtcNow; } } SetHeader("Cookie", text); } if (callback != null) { foreach (KeyValuePair <string, List <string> > header in Headers) { callback(header.Key, header.Value); } } }
private void SendHeaders(BinaryWriter stream) { SetHeader("Host", CurrentUri.Host); if (IsRedirected && !HasHeader("Referer")) { AddHeader("Referer", Uri.ToString()); } if (!HasHeader("Accept-Encoding")) { AddHeader("Accept-Encoding", "gzip, deflate, identity"); } if (!HasHeader("Connection")) { AddHeader("Connection", (!IsKeepAlive) ? "Close, TE" : "Keep-Alive, TE"); } if (!HasHeader("TE")) { AddHeader("TE", "chunked, identity"); } byte[] entityBody = GetEntityBody(); int num = (entityBody != null) ? entityBody.Length : 0; if (RawData == null) { byte[] array = ((object)FieldsImpl == null) ? null : FieldsImpl.get_data(); if (array != null && array.Length > 0 && !HasHeader("Content-Type")) { AddHeader("Content-Type", "application/x-www-form-urlencoded"); } } if (!HasHeader("Content-Length") && num != 0) { AddHeader("Content-Length", num.ToString()); } if (Credentials != null) { switch (Credentials.Type) { case AuthenticationTypes.Basic: SetHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Credentials.UserName + ":" + Credentials.Password))); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest = DigestStore.Get(CurrentUri); if (digest != null) { string value = digest.GenerateResponseHeader(this); if (!string.IsNullOrEmpty(value)) { SetHeader("Authorization", value); } } break; } } } foreach (KeyValuePair<string, List<string>> header in Headers) { byte[] aSCIIBytes = (header.Key + ": ").GetASCIIBytes(); for (int i = 0; i < header.Value.Count; i++) { stream.Write(aSCIIBytes); stream.Write(header.Value[i].GetASCIIBytes()); stream.Write(EOL); } } }
private void SendHeaders(BinaryWriter stream) { if (!this.HasHeader("Host")) { this.SetHeader("Host", this.CurrentUri.Authority); } if (this.IsRedirected && !this.HasHeader("Referer")) { this.AddHeader("Referer", this.Uri.ToString()); } if (!this.HasHeader("Accept-Encoding")) { this.AddHeader("Accept-Encoding", "gzip, identity"); } if (this.HasProxy && !this.HasHeader("Proxy-Connection")) { this.AddHeader("Proxy-Connection", (!this.IsKeepAlive) ? "Close" : "Keep-Alive"); } if (!this.HasHeader("Connection")) { this.AddHeader("Connection", (!this.IsKeepAlive) ? "Close, TE" : "Keep-Alive, TE"); } if (!this.HasHeader("TE")) { this.AddHeader("TE", "identity"); } if (!this.HasHeader("User-Agent")) { this.AddHeader("User-Agent", "BestHTTP"); } long num; if (this.UploadStream == null) { byte[] entityBody = this.GetEntityBody(); num = (long)((entityBody == null) ? 0 : entityBody.Length); if (this.RawData == null && (this.FormImpl != null || (this.FieldCollector != null && !this.FieldCollector.IsEmpty))) { this.SelectFormImplementation(); if (this.FormImpl != null) { this.FormImpl.PrepareRequest(this); } } } else { num = this.UploadStreamLength; if (num == -1L) { this.SetHeader("Transfer-Encoding", "Chunked"); } if (!this.HasHeader("Content-Type")) { this.SetHeader("Content-Type", "application/octet-stream"); } } if (num != -1L && !this.HasHeader("Content-Length")) { this.SetHeader("Content-Length", num.ToString()); } if (this.HasProxy && this.Proxy.Credentials != null) { switch (this.Proxy.Credentials.Type) { case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest = DigestStore.Get(this.Proxy.Address); if (digest != null) { string value = digest.GenerateResponseHeader(this, this.Proxy.Credentials); if (!string.IsNullOrEmpty(value)) { this.SetHeader("Proxy-Authorization", value); } } break; } case AuthenticationTypes.Basic: this.SetHeader("Proxy-Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password))); break; } } if (this.Credentials != null) { switch (this.Credentials.Type) { case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest2 = DigestStore.Get(this.CurrentUri); if (digest2 != null) { string value2 = digest2.GenerateResponseHeader(this, this.Credentials); if (!string.IsNullOrEmpty(value2)) { this.SetHeader("Authorization", value2); } } break; } case AuthenticationTypes.Basic: this.SetHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password))); break; } } List <Cookie> list = (!this.IsCookiesEnabled) ? null : CookieJar.Get(this.CurrentUri); if (list == null) { list = this.customCookies; } else if (this.customCookies != null) { list.AddRange(this.customCookies); } if (list != null && list.Count > 0) { bool flag = true; string text = string.Empty; bool flag2 = HTTPProtocolFactory.IsSecureProtocol(this.CurrentUri); SupportedProtocols protocolFromUri = HTTPProtocolFactory.GetProtocolFromUri(this.CurrentUri); foreach (Cookie current in list) { if ((!current.IsSecure || (current.IsSecure && flag2)) && (!current.IsHttpOnly || (current.IsHttpOnly && protocolFromUri == SupportedProtocols.HTTP))) { if (!flag) { text += "; "; } else { flag = false; } text += current.ToString(); current.LastAccess = DateTime.UtcNow; } } this.SetHeader("Cookie", text); } foreach (KeyValuePair <string, List <string> > current2 in this.Headers) { byte[] aSCIIBytes = (current2.Key + ": ").GetASCIIBytes(); for (int i = 0; i < current2.Value.Count; i++) { stream.Write(aSCIIBytes); stream.Write(current2.Value[i].GetASCIIBytes()); stream.Write(HTTPRequest.EOL); } } }
private void ThreadFunc(object param) { bool flag = false; bool flag2 = false; HTTPConnection.RetryCauses retryCauses = HTTPConnection.RetryCauses.None; try { if (!this.HasProxy && this.CurrentRequest.HasProxy) { this.Proxy = this.CurrentRequest.Proxy; } if (!this.TryLoadAllFromCache()) { if (this.Client != null && !this.Client.IsConnected()) { this.Close(); } while (true) { if (retryCauses == HTTPConnection.RetryCauses.Reconnect) { this.Close(); Thread.Sleep(100); } this.LastProcessedUri = this.CurrentRequest.CurrentUri; retryCauses = HTTPConnection.RetryCauses.None; this.Connect(); if (this.State == HTTPConnectionStates.AbortRequested) { break; } if (!this.CurrentRequest.DisableCache) { HTTPCacheService.SetHeaders(this.CurrentRequest); } bool flag3 = this.CurrentRequest.SendOutTo(this.Stream); if (!flag3) { this.Close(); if (this.State == HTTPConnectionStates.TimedOut) { goto Block_13; } if (!flag) { flag = true; retryCauses = HTTPConnection.RetryCauses.Reconnect; } } if (flag3) { bool flag4 = this.Receive(); if (this.State == HTTPConnectionStates.TimedOut) { goto Block_16; } if (!flag4 && !flag) { flag = true; retryCauses = HTTPConnection.RetryCauses.Reconnect; } if (this.CurrentRequest.Response != null) { int statusCode = this.CurrentRequest.Response.StatusCode; switch (statusCode) { case 301: case 302: case 307: case 308: { if (this.CurrentRequest.RedirectCount >= this.CurrentRequest.MaxRedirects) { goto IL_3F7; } this.CurrentRequest.RedirectCount++; string firstHeaderValue = this.CurrentRequest.Response.GetFirstHeaderValue("location"); if (string.IsNullOrEmpty(firstHeaderValue)) { goto IL_3C9; } Uri redirectUri = this.GetRedirectUri(firstHeaderValue); if (!this.CurrentRequest.CallOnBeforeRedirection(redirectUri)) { HTTPManager.Logger.Information("HTTPConnection", "OnBeforeRedirection returned False"); goto IL_3F7; } this.CurrentRequest.RemoveHeader("Host"); this.CurrentRequest.SetHeader("Referer", this.CurrentRequest.CurrentUri.ToString()); this.CurrentRequest.RedirectUri = redirectUri; this.CurrentRequest.Response = null; bool flag5 = true; this.CurrentRequest.IsRedirected = flag5; flag2 = flag5; goto IL_3F7; } case 303: case 304: case 305: case 306: IL_186: if (statusCode == 401) { string firstHeaderValue2 = this.CurrentRequest.Response.GetFirstHeaderValue("www-authenticate"); if (!string.IsNullOrEmpty(firstHeaderValue2)) { Digest orCreate = DigestStore.GetOrCreate(this.CurrentRequest.CurrentUri); orCreate.ParseChallange(firstHeaderValue2); if (this.CurrentRequest.Credentials != null && orCreate.IsUriProtected(this.CurrentRequest.CurrentUri) && (!this.CurrentRequest.HasHeader("Authorization") || orCreate.Stale)) { retryCauses = HTTPConnection.RetryCauses.Authenticate; } } goto IL_3F7; } if (statusCode != 407) { goto IL_3F7; } if (this.CurrentRequest.HasProxy) { string firstHeaderValue3 = this.CurrentRequest.Response.GetFirstHeaderValue("proxy-authenticate"); if (!string.IsNullOrEmpty(firstHeaderValue3)) { Digest orCreate2 = DigestStore.GetOrCreate(this.CurrentRequest.Proxy.Address); orCreate2.ParseChallange(firstHeaderValue3); if (this.CurrentRequest.Proxy.Credentials != null && orCreate2.IsUriProtected(this.CurrentRequest.Proxy.Address) && (!this.CurrentRequest.HasHeader("Proxy-Authorization") || orCreate2.Stale)) { retryCauses = HTTPConnection.RetryCauses.ProxyAuthenticate; } } } goto IL_3F7; } goto IL_186; IL_3F7: if (this.CurrentRequest.IsCookiesEnabled) { CookieJar.Set(this.CurrentRequest.Response); } this.TryStoreInCache(); if (this.CurrentRequest.Response == null || this.CurrentRequest.Response.HasHeaderWithValue("connection", "close") || this.CurrentRequest.UseAlternateSSL) { this.Close(); } } } if (retryCauses == HTTPConnection.RetryCauses.None) { goto Block_37; } } throw new Exception("AbortRequested"); Block_13: throw new Exception("AbortRequested"); Block_16: throw new Exception("AbortRequested"); IL_3C9: throw new MissingFieldException(string.Format("Got redirect status({0}) without 'location' header!", this.CurrentRequest.Response.StatusCode.ToString())); Block_37 :; } } catch (TimeoutException exception) { this.CurrentRequest.Response = null; this.CurrentRequest.Exception = exception; this.CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut; this.Close(); } catch (Exception exception2) { if (this.CurrentRequest != null) { if (this.CurrentRequest.UseStreaming) { HTTPCacheService.DeleteEntity(this.CurrentRequest.CurrentUri, true); } this.CurrentRequest.Response = null; HTTPConnectionStates state = this.State; if (state != HTTPConnectionStates.AbortRequested) { if (state != HTTPConnectionStates.TimedOut) { this.CurrentRequest.Exception = exception2; this.CurrentRequest.State = HTTPRequestStates.Error; } else { this.CurrentRequest.State = HTTPRequestStates.TimedOut; } } else { this.CurrentRequest.State = HTTPRequestStates.Aborted; } } this.Close(); } finally { if (this.CurrentRequest != null) { object locker = HTTPManager.Locker; lock (locker) { if (this.CurrentRequest != null && this.CurrentRequest.Response != null && this.CurrentRequest.Response.IsUpgraded) { this.State = HTTPConnectionStates.Upgraded; } else { this.State = ((!flag2) ? ((this.Client != null) ? HTTPConnectionStates.WaitForRecycle : HTTPConnectionStates.Closed) : HTTPConnectionStates.Redirected); } if (this.CurrentRequest.State == HTTPRequestStates.Processing && (this.State == HTTPConnectionStates.Closed || this.State == HTTPConnectionStates.WaitForRecycle)) { this.CurrentRequest.State = HTTPRequestStates.Finished; } if (this.CurrentRequest.State == HTTPRequestStates.ConnectionTimedOut) { this.State = HTTPConnectionStates.Closed; } this.LastProcessTime = DateTime.UtcNow; } HTTPCacheService.SaveLibrary(); CookieJar.Persist(); } } }
/// <summary> /// Writes out the Headers to the stream. /// </summary> /// <param name="stream"></param> private void SendHeaders(BinaryWriter stream) { if (!HasHeader("Host")) { SetHeader("Host", CurrentUri.Host); } if (IsRedirected && !HasHeader("Referer")) { AddHeader("Referer", Uri.ToString()); } if (!HasHeader("Accept-Encoding")) { AddHeader("Accept-Encoding", "gzip, identity"); } if (HasProxy && !HasHeader("Proxy-Connection")) { AddHeader("Proxy-Connection", IsKeepAlive ? "Keep-Alive" : "Close"); } if (!HasHeader("Connection")) { AddHeader("Connection", IsKeepAlive ? "Keep-Alive, TE" : "Close, TE"); } if (!HasHeader("TE")) { AddHeader("TE", "identity"); } if (!HasHeader("User-Agent")) { AddHeader("User-Agent", "BestHTTP"); } byte[] entityBody = GetEntityBody(); int contentLength = entityBody != null ? entityBody.Length : 0; if (RawData == null && (FormImpl != null || (FieldCollector != null && !FieldCollector.IsEmpty))) { SelectFormImplementation(); if (FormImpl != null) { FormImpl.PrepareRequest(this); } } if (!HasHeader("Content-Length") && contentLength != 0) { AddHeader("Content-Length", contentLength.ToString()); } // 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 SetHeader("Proxy-Authorization", string.Concat("Basic ", Convert.ToBase64String(Encoding.UTF8.GetBytes(Credentials.UserName + ":" + Credentials.Password)))); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: var digest = DigestStore.Get(Proxy.Address); if (digest != null) { string authentication = digest.GenerateResponseHeader(this, Proxy.Credentials); if (!string.IsNullOrEmpty(authentication)) { SetHeader("Proxy-Authorization", authentication); } } break; } } // Server authentication if (Credentials != null) { switch (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 SetHeader("Authorization", string.Concat("Basic ", Convert.ToBase64String(Encoding.UTF8.GetBytes(Credentials.UserName + ":" + Credentials.Password)))); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: var digest = DigestStore.Get(this.CurrentUri); if (digest != null) { string authentication = digest.GenerateResponseHeader(this, Credentials); if (!string.IsNullOrEmpty(authentication)) { SetHeader("Authorization", authentication); } } break; } } // Cookies if (IsCookiesEnabled) { var cookies = CookieJar.Get(CurrentUri); // http://tools.ietf.org/html/rfc6265#section-5.4 // -When the user agent generates an HTTP request, the user agent MUST NOT attach more than one Cookie header field. if (cookies != null && cookies.Count > 0) { // TODO: // 2. The user agent SHOULD sort the cookie-list in the following order: // * Cookies with longer paths are listed before cookies with shorter paths. // * Among cookies that have equal-length path fields, cookies with earlier creation-times are listed before cookies with later creation-times. bool first = true; string cookieStr = string.Empty; foreach (var cookie in cookies) { if ((!cookie.IsSecure || (cookie.IsSecure && HTTPProtocolFactory.IsSecureProtocol(CurrentUri))) && (!cookie.IsHttpOnly || (cookie.IsHttpOnly && HTTPProtocolFactory.GetProtocolFromUri(CurrentUri) == SupportedProtocols.HTTP))) { if (!first) { cookieStr += "; "; } else { first = false; } cookieStr += cookie.ToString(); // 3. Update the last-access-time of each cookie in the cookie-list to the current date and time. cookie.LastAccess = DateTime.UtcNow; } } SetHeader("Cookie", cookieStr); } } // Write out the headers to the stream foreach (var kvp in Headers) { byte[] headerName = string.Concat(kvp.Key, ": ").GetASCIIBytes(); for (int i = 0; i < kvp.Value.Count; ++i) { stream.Write(headerName); stream.Write(kvp.Value[i].GetASCIIBytes()); stream.Write(EOL); } } }
private void Connect() { Uri uri = !base.CurrentRequest.HasProxy ? base.CurrentRequest.CurrentUri : base.CurrentRequest.Proxy.Address; if (this.Client == null) { this.Client = new TcpClient(); } if (!this.Client.Connected) { this.Client.ConnectTimeout = base.CurrentRequest.ConnectTimeout; if (HTTPManager.Logger.Level == Loglevels.All) { HTTPManager.Logger.Verbose("HTTPConnection", $"'{base.CurrentRequest.CurrentUri.ToString()}' - Connecting to {uri.Host}:{uri.Port.ToString()}"); } this.Client.Connect(uri.Host, uri.Port); if (HTTPManager.Logger.Level <= Loglevels.Information) { HTTPManager.Logger.Information("HTTPConnection", "Connected to " + uri.Host + ":" + uri.Port.ToString()); } } else if (HTTPManager.Logger.Level <= Loglevels.Information) { HTTPManager.Logger.Information("HTTPConnection", "Already connected to " + uri.Host + ":" + uri.Port.ToString()); } base.StartTime = DateTime.UtcNow; if (this.Stream == null) { bool flag = HTTPProtocolFactory.IsSecureProtocol(base.CurrentRequest.CurrentUri); this.Stream = this.Client.GetStream(); if (base.HasProxy && (!base.Proxy.IsTransparent || (flag && base.Proxy.NonTransparentForHTTPS))) { bool flag2; BinaryWriter stream = new BinaryWriter(this.Stream); do { flag2 = false; string str = $"CONNECT {base.CurrentRequest.CurrentUri.Host}:{base.CurrentRequest.CurrentUri.Port} HTTP/1.1"; HTTPManager.Logger.Information("HTTPConnection", "Sending " + str); stream.SendAsASCII(str); stream.Write(HTTPRequest.EOL); stream.SendAsASCII("Proxy-Connection: Keep-Alive"); stream.Write(HTTPRequest.EOL); stream.SendAsASCII("Connection: Keep-Alive"); stream.Write(HTTPRequest.EOL); stream.SendAsASCII($"Host: {base.CurrentRequest.CurrentUri.Host}:{base.CurrentRequest.CurrentUri.Port}"); stream.Write(HTTPRequest.EOL); if (base.HasProxy && (base.Proxy.Credentials != null)) { switch (base.Proxy.Credentials.Type) { case AuthenticationTypes.Basic: stream.Write($"Proxy-Authorization: {("Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(base.Proxy.Credentials.UserName + ":" + base.Proxy.Credentials.Password)))}".GetASCIIBytes()); stream.Write(HTTPRequest.EOL); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest = DigestStore.Get(base.Proxy.Address); if (digest != null) { string str2 = digest.GenerateResponseHeader(base.CurrentRequest, base.Proxy.Credentials); if (!string.IsNullOrEmpty(str2)) { stream.Write($"Proxy-Authorization: {str2}".GetASCIIBytes()); stream.Write(HTTPRequest.EOL); } } break; } } } stream.Write(HTTPRequest.EOL); stream.Flush(); base.CurrentRequest.ProxyResponse = new HTTPResponse(base.CurrentRequest, this.Stream, false, false); if (!base.CurrentRequest.ProxyResponse.Receive(-1, true)) { throw new Exception("Connection to the Proxy Server failed!"); } if (HTTPManager.Logger.Level <= Loglevels.Information) { object[] objArray1 = new object[] { "Proxy returned - status code: ", base.CurrentRequest.ProxyResponse.StatusCode, " message: ", base.CurrentRequest.ProxyResponse.Message }; HTTPManager.Logger.Information("HTTPConnection", string.Concat(objArray1)); } if (base.CurrentRequest.ProxyResponse.StatusCode == 0x197) { string str3 = DigestStore.FindBest(base.CurrentRequest.ProxyResponse.GetHeaderValues("proxy-authenticate")); if (!string.IsNullOrEmpty(str3)) { Digest orCreate = DigestStore.GetOrCreate(base.Proxy.Address); orCreate.ParseChallange(str3); if (((base.Proxy.Credentials != null) && orCreate.IsUriProtected(base.Proxy.Address)) && (!base.CurrentRequest.HasHeader("Proxy-Authorization") || orCreate.Stale)) { flag2 = true; } } } else if (!base.CurrentRequest.ProxyResponse.IsSuccess) { throw new Exception($"Proxy returned Status Code: " { base.CurrentRequest.ProxyResponse.StatusCode } ", Message: " { base.CurrentRequest.ProxyResponse.Message } " and Response: {base.CurrentRequest.ProxyResponse.DataAsText}"); } }while (flag2); } if (flag) { if (base.CurrentRequest.UseAlternateSSL) { TlsClientProtocol protocol = new TlsClientProtocol(this.Client.GetStream(), new SecureRandom()); List <string> hostNames = new List <string>(1) { base.CurrentRequest.CurrentUri.Host }; protocol.Connect(new LegacyTlsClient(base.CurrentRequest.CurrentUri, (base.CurrentRequest.CustomCertificateVerifyer != null) ? base.CurrentRequest.CustomCertificateVerifyer : new AlwaysValidVerifyer(), base.CurrentRequest.CustomClientCredentialsProvider, hostNames)); this.Stream = protocol.Stream; } else { SslStream stream = new SslStream(this.Client.GetStream(), false, (sender, cert, chain, errors) => base.CurrentRequest.CallCustomCertificationValidator(cert, chain)); if (!stream.IsAuthenticated) { stream.AuthenticateAsClient(base.CurrentRequest.CurrentUri.Host); } this.Stream = stream; } } } }
protected override void ThreadFunc(object param) { bool flag = false; bool flag2 = false; RetryCauses none = RetryCauses.None; try { if (!base.HasProxy && base.CurrentRequest.HasProxy) { base.Proxy = base.CurrentRequest.Proxy; } if (!this.TryLoadAllFromCache()) { if ((this.Client != null) && !this.Client.IsConnected()) { this.Close(); } do { if (none == RetryCauses.Reconnect) { this.Close(); Thread.Sleep(100); } base.LastProcessedUri = base.CurrentRequest.CurrentUri; none = RetryCauses.None; this.Connect(); if (base.State == HTTPConnectionStates.AbortRequested) { throw new Exception("AbortRequested"); } if (!base.CurrentRequest.DisableCache) { HTTPCacheService.SetHeaders(base.CurrentRequest); } bool flag3 = false; try { this.Client.NoDelay = base.CurrentRequest.TryToMinimizeTCPLatency; base.CurrentRequest.SendOutTo(this.Stream); flag3 = true; } catch (Exception exception) { this.Close(); if ((base.State == HTTPConnectionStates.TimedOut) || (base.State == HTTPConnectionStates.AbortRequested)) { throw new Exception("AbortRequested"); } if (flag || base.CurrentRequest.DisableRetry) { throw exception; } flag = true; none = RetryCauses.Reconnect; } if (flag3) { bool flag4 = this.Receive(); if ((base.State == HTTPConnectionStates.TimedOut) || (base.State == HTTPConnectionStates.AbortRequested)) { throw new Exception("AbortRequested"); } if ((!flag4 && !flag) && !base.CurrentRequest.DisableRetry) { flag = true; none = RetryCauses.Reconnect; } if (base.CurrentRequest.Response != null) { if (base.CurrentRequest.IsCookiesEnabled) { CookieJar.Set(base.CurrentRequest.Response); } switch (base.CurrentRequest.Response.StatusCode) { case 0x12d: case 0x12e: case 0x133: case 0x134: if (base.CurrentRequest.RedirectCount < base.CurrentRequest.MaxRedirects) { HTTPRequest currentRequest = base.CurrentRequest; currentRequest.RedirectCount++; string firstHeaderValue = base.CurrentRequest.Response.GetFirstHeaderValue("location"); if (string.IsNullOrEmpty(firstHeaderValue)) { throw new MissingFieldException($"Got redirect status({base.CurrentRequest.Response.StatusCode.ToString()}) without 'location' header!"); } Uri redirectUri = this.GetRedirectUri(firstHeaderValue); if (HTTPManager.Logger.Level == Loglevels.All) { HTTPManager.Logger.Verbose("HTTPConnection", string.Format("{0} - Redirected to Location: '{1}' redirectUri: '{1}'", base.CurrentRequest.CurrentUri.ToString(), firstHeaderValue, redirectUri)); } if (!base.CurrentRequest.CallOnBeforeRedirection(redirectUri)) { HTTPManager.Logger.Information("HTTPConnection", "OnBeforeRedirection returned False"); } else { base.CurrentRequest.RemoveHeader("Host"); base.CurrentRequest.SetHeader("Referer", base.CurrentRequest.CurrentUri.ToString()); base.CurrentRequest.RedirectUri = redirectUri; base.CurrentRequest.Response = null; bool flag5 = true; base.CurrentRequest.IsRedirected = flag5; flag2 = flag5; } } break; case 0x191: { string str = DigestStore.FindBest(base.CurrentRequest.Response.GetHeaderValues("www-authenticate")); if (!string.IsNullOrEmpty(str)) { Digest orCreate = DigestStore.GetOrCreate(base.CurrentRequest.CurrentUri); orCreate.ParseChallange(str); if (((base.CurrentRequest.Credentials != null) && orCreate.IsUriProtected(base.CurrentRequest.CurrentUri)) && (!base.CurrentRequest.HasHeader("Authorization") || orCreate.Stale)) { none = RetryCauses.Authenticate; } } break; } case 0x197: if (base.CurrentRequest.HasProxy) { string str2 = DigestStore.FindBest(base.CurrentRequest.Response.GetHeaderValues("proxy-authenticate")); if (!string.IsNullOrEmpty(str2)) { Digest orCreate = DigestStore.GetOrCreate(base.CurrentRequest.Proxy.Address); orCreate.ParseChallange(str2); if (((base.CurrentRequest.Proxy.Credentials != null) && orCreate.IsUriProtected(base.CurrentRequest.Proxy.Address)) && (!base.CurrentRequest.HasHeader("Proxy-Authorization") || orCreate.Stale)) { none = RetryCauses.ProxyAuthenticate; } } } break; } this.TryStoreInCache(); if ((base.CurrentRequest.Response == null) || !base.CurrentRequest.Response.IsClosedManually) { bool flag6 = (base.CurrentRequest.Response == null) || base.CurrentRequest.Response.HasHeaderWithValue("connection", "close"); bool flag7 = !base.CurrentRequest.IsKeepAlive; if (flag6 || flag7) { this.Close(); } else if (base.CurrentRequest.Response != null) { List <string> headerValues = base.CurrentRequest.Response.GetHeaderValues("keep-alive"); if ((headerValues != null) && (headerValues.Count > 0)) { if (this.KeepAlive == null) { this.KeepAlive = new KeepAliveHeader(); } this.KeepAlive.Parse(headerValues); } } } } } }while (none != RetryCauses.None); } } catch (TimeoutException exception2) { base.CurrentRequest.Response = null; base.CurrentRequest.Exception = exception2; base.CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut; this.Close(); } catch (Exception exception3) { if (base.CurrentRequest != null) { if (base.CurrentRequest.UseStreaming) { HTTPCacheService.DeleteEntity(base.CurrentRequest.CurrentUri, true); } base.CurrentRequest.Response = null; switch (base.State) { case HTTPConnectionStates.AbortRequested: case HTTPConnectionStates.Closed: base.CurrentRequest.State = HTTPRequestStates.Aborted; goto Label_0685; case HTTPConnectionStates.TimedOut: base.CurrentRequest.State = HTTPRequestStates.TimedOut; goto Label_0685; } base.CurrentRequest.Exception = exception3; base.CurrentRequest.State = HTTPRequestStates.Error; } Label_0685: this.Close(); } finally { if (base.CurrentRequest != null) { object locker = HTTPManager.Locker; lock (locker) { if (((base.CurrentRequest != null) && (base.CurrentRequest.Response != null)) && base.CurrentRequest.Response.IsUpgraded) { base.State = HTTPConnectionStates.Upgraded; } else { base.State = !flag2 ? ((this.Client != null) ? HTTPConnectionStates.WaitForRecycle : HTTPConnectionStates.Closed) : HTTPConnectionStates.Redirected; } if ((base.CurrentRequest.State == HTTPRequestStates.Processing) && ((base.State == HTTPConnectionStates.Closed) || (base.State == HTTPConnectionStates.WaitForRecycle))) { if (base.CurrentRequest.Response != null) { base.CurrentRequest.State = HTTPRequestStates.Finished; } else { base.CurrentRequest.Exception = new Exception($"Remote server closed the connection before sending response header! Previous request state: {base.CurrentRequest.State.ToString()}. Connection state: {base.State.ToString()}"); base.CurrentRequest.State = HTTPRequestStates.Error; } } if (base.CurrentRequest.State == HTTPRequestStates.ConnectionTimedOut) { base.State = HTTPConnectionStates.Closed; } base.LastProcessTime = DateTime.UtcNow; if (base.OnConnectionRecycled != null) { base.RecycleNow(); } } HTTPCacheService.SaveLibrary(); CookieJar.Persist(); } } }
protected override void ThreadFunc(object param) { bool flag = false; bool flag2 = false; RetryCauses retryCauses = RetryCauses.None; try { if (!base.HasProxy && base.CurrentRequest.HasProxy) { base.Proxy = base.CurrentRequest.Proxy; } if (!TryLoadAllFromCache()) { if (Client != null && !Client.IsConnected()) { Close(); } while (true) { if (retryCauses == RetryCauses.Reconnect) { Close(); Thread.Sleep(100); } base.LastProcessedUri = base.CurrentRequest.CurrentUri; retryCauses = RetryCauses.None; Connect(); if (base.State == HTTPConnectionStates.AbortRequested) { throw new Exception("AbortRequested"); } if (!base.CurrentRequest.DisableCache) { HTTPCacheService.SetHeaders(base.CurrentRequest); } bool flag3 = false; try { base.CurrentRequest.SendOutTo(Stream); flag3 = true; } catch (Exception ex) { Close(); if (base.State == HTTPConnectionStates.TimedOut) { throw new Exception("AbortRequested"); } if (flag || base.CurrentRequest.DisableRetry) { throw ex; } flag = true; retryCauses = RetryCauses.Reconnect; } if (flag3) { bool flag4 = Receive(); if (base.State == HTTPConnectionStates.TimedOut) { break; } if (!flag4 && !flag && !base.CurrentRequest.DisableRetry) { flag = true; retryCauses = RetryCauses.Reconnect; } if (base.CurrentRequest.Response != null) { if (base.CurrentRequest.IsCookiesEnabled) { CookieJar.Set(base.CurrentRequest.Response); } switch (base.CurrentRequest.Response.StatusCode) { case 401: { string text2 = DigestStore.FindBest(base.CurrentRequest.Response.GetHeaderValues("www-authenticate")); if (!string.IsNullOrEmpty(text2)) { Digest orCreate2 = DigestStore.GetOrCreate(base.CurrentRequest.CurrentUri); orCreate2.ParseChallange(text2); if (base.CurrentRequest.Credentials != null && orCreate2.IsUriProtected(base.CurrentRequest.CurrentUri) && (!base.CurrentRequest.HasHeader("Authorization") || orCreate2.Stale)) { retryCauses = RetryCauses.Authenticate; } } break; } case 407: if (base.CurrentRequest.HasProxy) { string text = DigestStore.FindBest(base.CurrentRequest.Response.GetHeaderValues("proxy-authenticate")); if (!string.IsNullOrEmpty(text)) { Digest orCreate = DigestStore.GetOrCreate(base.CurrentRequest.Proxy.Address); orCreate.ParseChallange(text); if (base.CurrentRequest.Proxy.Credentials != null && orCreate.IsUriProtected(base.CurrentRequest.Proxy.Address) && (!base.CurrentRequest.HasHeader("Proxy-Authorization") || orCreate.Stale)) { retryCauses = RetryCauses.ProxyAuthenticate; } } } break; case 301: case 302: case 307: case 308: if (base.CurrentRequest.RedirectCount < base.CurrentRequest.MaxRedirects) { base.CurrentRequest.RedirectCount++; string firstHeaderValue = base.CurrentRequest.Response.GetFirstHeaderValue("location"); if (string.IsNullOrEmpty(firstHeaderValue)) { throw new MissingFieldException($"Got redirect status({base.CurrentRequest.Response.StatusCode.ToString()}) without 'location' header!"); } Uri redirectUri = GetRedirectUri(firstHeaderValue); if (!base.CurrentRequest.CallOnBeforeRedirection(redirectUri)) { HTTPManager.Logger.Information("HTTPConnection", "OnBeforeRedirection returned False"); } else { base.CurrentRequest.RemoveHeader("Host"); base.CurrentRequest.SetHeader("Referer", base.CurrentRequest.CurrentUri.ToString()); base.CurrentRequest.RedirectUri = redirectUri; base.CurrentRequest.Response = null; bool flag5 = true; base.CurrentRequest.IsRedirected = flag5; flag2 = flag5; } } break; } TryStoreInCache(); if (base.CurrentRequest.Response == null || (!base.CurrentRequest.Response.IsClosedManually && base.CurrentRequest.Response.HasHeaderWithValue("connection", "close"))) { Close(); } } } if (retryCauses == RetryCauses.None) { return; } } throw new Exception("AbortRequested"); } } catch (TimeoutException exception) { base.CurrentRequest.Response = null; base.CurrentRequest.Exception = exception; base.CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut; Close(); } catch (Exception exception2) { if (base.CurrentRequest != null) { if (base.CurrentRequest.UseStreaming) { HTTPCacheService.DeleteEntity(base.CurrentRequest.CurrentUri); } base.CurrentRequest.Response = null; switch (base.State) { case HTTPConnectionStates.AbortRequested: case HTTPConnectionStates.Closed: base.CurrentRequest.State = HTTPRequestStates.Aborted; break; case HTTPConnectionStates.TimedOut: base.CurrentRequest.State = HTTPRequestStates.TimedOut; break; default: base.CurrentRequest.Exception = exception2; base.CurrentRequest.State = HTTPRequestStates.Error; break; } } Close(); } finally { if (base.CurrentRequest != null) { lock (HTTPManager.Locker) { if (base.CurrentRequest != null && base.CurrentRequest.Response != null && base.CurrentRequest.Response.IsUpgraded) { base.State = HTTPConnectionStates.Upgraded; } else { base.State = (flag2 ? HTTPConnectionStates.Redirected : ((Client != null) ? HTTPConnectionStates.WaitForRecycle : HTTPConnectionStates.Closed)); } if (base.CurrentRequest.State == HTTPRequestStates.Processing && (base.State == HTTPConnectionStates.Closed || base.State == HTTPConnectionStates.WaitForRecycle)) { if (base.CurrentRequest.Response != null) { base.CurrentRequest.State = HTTPRequestStates.Finished; } else { base.CurrentRequest.State = HTTPRequestStates.Error; } } if (base.CurrentRequest.State == HTTPRequestStates.ConnectionTimedOut) { base.State = HTTPConnectionStates.Closed; } LastProcessTime = DateTime.UtcNow; if (OnConnectionRecycled != null) { RecycleNow(); } } HTTPCacheService.SaveLibrary(); CookieJar.Persist(); } } }
private void Connect() { Uri uri = (!base.CurrentRequest.HasProxy) ? base.CurrentRequest.CurrentUri : base.CurrentRequest.Proxy.Address; if (Client == null) { Client = new TcpClient(); } if (!Client.Connected) { Client.ConnectTimeout = base.CurrentRequest.ConnectTimeout; Client.Connect(uri.Host, uri.Port); if (HTTPManager.Logger.Level <= Loglevels.Information) { HTTPManager.Logger.Information("HTTPConnection", "Connected to " + uri.Host + ":" + uri.Port.ToString()); } } else if (HTTPManager.Logger.Level <= Loglevels.Information) { HTTPManager.Logger.Information("HTTPConnection", "Already connected to " + uri.Host + ":" + uri.Port.ToString()); } lock (HTTPManager.Locker) { base.StartTime = DateTime.UtcNow; } if (Stream == null) { bool flag = HTTPProtocolFactory.IsSecureProtocol(base.CurrentRequest.CurrentUri); if (base.HasProxy && (!base.Proxy.IsTransparent || (flag && base.Proxy.NonTransparentForHTTPS))) { Stream = Client.GetStream(); BinaryWriter binaryWriter = new BinaryWriter(Stream); bool flag2; do { flag2 = false; binaryWriter.SendAsASCII($"CONNECT {base.CurrentRequest.CurrentUri.Host}:{base.CurrentRequest.CurrentUri.Port} HTTP/1.1"); binaryWriter.Write(HTTPRequest.EOL); binaryWriter.SendAsASCII("Proxy-Connection: Keep-Alive"); binaryWriter.Write(HTTPRequest.EOL); binaryWriter.SendAsASCII("Connection: Keep-Alive"); binaryWriter.Write(HTTPRequest.EOL); binaryWriter.SendAsASCII($"Host: {base.CurrentRequest.CurrentUri.Host}:{base.CurrentRequest.CurrentUri.Port}"); binaryWriter.Write(HTTPRequest.EOL); if (base.HasProxy && base.Proxy.Credentials != null) { switch (base.Proxy.Credentials.Type) { case AuthenticationTypes.Basic: binaryWriter.Write(string.Format("Proxy-Authorization: {0}", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(base.Proxy.Credentials.UserName + ":" + base.Proxy.Credentials.Password))).GetASCIIBytes()); binaryWriter.Write(HTTPRequest.EOL); break; case AuthenticationTypes.Unknown: case AuthenticationTypes.Digest: { Digest digest = DigestStore.Get(base.Proxy.Address); if (digest != null) { string text = digest.GenerateResponseHeader(base.CurrentRequest, base.Proxy.Credentials); if (!string.IsNullOrEmpty(text)) { binaryWriter.Write($"Proxy-Authorization: {text}".GetASCIIBytes()); binaryWriter.Write(HTTPRequest.EOL); } } break; } } } binaryWriter.Write(HTTPRequest.EOL); binaryWriter.Flush(); base.CurrentRequest.ProxyResponse = new HTTPResponse(base.CurrentRequest, Stream, isStreamed: false, isFromCache: false); if (!base.CurrentRequest.ProxyResponse.Receive()) { throw new Exception("Connection to the Proxy Server failed!"); } if (HTTPManager.Logger.Level <= Loglevels.Information) { HTTPManager.Logger.Information("HTTPConnection", "Proxy returned - status code: " + base.CurrentRequest.ProxyResponse.StatusCode + " message: " + base.CurrentRequest.ProxyResponse.Message); } int statusCode = base.CurrentRequest.ProxyResponse.StatusCode; if (statusCode == 407) { string text2 = DigestStore.FindBest(base.CurrentRequest.ProxyResponse.GetHeaderValues("proxy-authenticate")); if (!string.IsNullOrEmpty(text2)) { Digest orCreate = DigestStore.GetOrCreate(base.Proxy.Address); orCreate.ParseChallange(text2); if (base.Proxy.Credentials != null && orCreate.IsUriProtected(base.Proxy.Address) && (!base.CurrentRequest.HasHeader("Proxy-Authorization") || orCreate.Stale)) { flag2 = true; } } } else if (!base.CurrentRequest.ProxyResponse.IsSuccess) { throw new Exception($"Proxy returned Status Code: \"{base.CurrentRequest.ProxyResponse.StatusCode}\", Message: \"{base.CurrentRequest.ProxyResponse.Message}\" and Response: {base.CurrentRequest.ProxyResponse.DataAsText}"); } }while (flag2); } if (flag) { if (base.CurrentRequest.UseAlternateSSL) { TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(Client.GetStream(), new SecureRandom()); List <string> list = new List <string>(1); list.Add(base.CurrentRequest.CurrentUri.Host); TlsClientProtocol tlsClientProtocol2 = tlsClientProtocol; Uri currentUri = base.CurrentRequest.CurrentUri; object verifyer; if (base.CurrentRequest.CustomCertificateVerifyer == null) { ICertificateVerifyer certificateVerifyer = new AlwaysValidVerifyer(); verifyer = certificateVerifyer; } else { verifyer = base.CurrentRequest.CustomCertificateVerifyer; } tlsClientProtocol2.Connect(new LegacyTlsClient(currentUri, (ICertificateVerifyer)verifyer, base.CurrentRequest.CustomClientCredentialsProvider, list)); Stream = tlsClientProtocol.Stream; } else { SslStream sslStream = new SslStream(Client.GetStream(), leaveInnerStreamOpen: false, (object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors) => base.CurrentRequest.CallCustomCertificationValidator(cert, chain)); if (!sslStream.IsAuthenticated) { sslStream.AuthenticateAsClient(base.CurrentRequest.CurrentUri.Host); } Stream = sslStream; } } else { Stream = Client.GetStream(); } } }