def determine_auth_type(cls, url, proxies=None, timeout=None, cert=None, logger=None):
     """
     Determine the authentication type that is appropriate to authenticate to the given web-server.
     
     Argument:
     url -- The url to connect to. This object ought to be an instance derived from using urlparse
     proxies -- The proxies to use
     timeout -- The amount of time to quit waiting on a connection
     cert -- A tuple representing the certificate to use
     logger -- The logger object to use for logging
     """
     
     # Perform a request to the URL and see what authentication method is required
     # Make the client
     http = requests.get(url.geturl(), proxies=proxies, timeout=timeout, cert=cert, verify=False)
     
     try:
         
         auth_header = http.headers['WWW-Authenticate']
         
         if auth_header is not None:
             m = re.search('^([a-zA-Z0-9]+) ', auth_header)
             auth_type = m.group(1)
             return auth_type.lower()
         
     except Exception:
         if logger:
             logger.exception("Unable to determine authentication type") 
Example #2
0
    def determine_auth_type(cls,
                            url,
                            proxies=None,
                            timeout=None,
                            cert=None,
                            logger=None):
        """
        Determine the authentication type that is appropriate to authenticate to the given web-server.
        
        Argument:
        url -- The url to connect to. This object ought to be an instance derived from using urlparse
        proxies -- The proxies to use
        timeout -- The amount of time to quit waiting on a connection
        cert -- A tuple representing the certificate to use
        logger -- The logger object to use for logging
        """

        # Perform a request to the URL and see what authentication method is required
        try:

            # Make the GET
            http = requests.get(url.geturl(),
                                proxies=proxies,
                                timeout=timeout,
                                cert=cert,
                                verify=False)

            # Find the authentication header irrespective of case
            auth_header_value = None

            for header, value in http.headers.items():
                if header.lower() == 'www-authenticate':
                    auth_header_value = value
                    break

            # Determine if the authentication header is present and use it to determine the authentication type
            if auth_header_value is not None:

                # Handle the pesky cases where a comma separated value is provided in the header for NTLM negotiation (like "negotiate, ntlm")
                if 'ntlm' in auth_header_value.lower():
                    return cls.HTTP_AUTH_NTLM

                # Otherwise, check the HTTP header for the authentication header
                m = re.search('^([a-zA-Z0-9]+)', auth_header_value)
                auth_type = m.group(1)
                return auth_type.lower()

            # No authentication header is present
            else:
                if logger:
                    logger.warn(
                        "Unable to determine authentication type (no www-authenticate header); will default to basic authentication"
                    )

                return cls.HTTP_AUTH_NONE

        except Exception:

            if logger:
                logger.exception("Unable to determine authentication type")
Example #3
0
    def test_is_exception_for_timeout(self):
        try:
            r = requests.get('https://192.168.30.23/')
        except requests.exceptions.ConnectionError as e:

            if not WebPing.isExceptionForTimeout(e):
                print(e)
            self.assertTrue(WebPing.isExceptionForTimeout(e))
    def determine_auth_type(cls, url, proxies=None, timeout=None, cert=None, logger=None):
        """
        Determine the authentication type that is appropriate to authenticate to the given
        web-server.

        Argument:
        url -- The url to connect to. This object ought to be an instance derived from using urlparse
        proxies -- The proxies to use
        timeout -- The amount of time to quit waiting on a connection
        cert -- A tuple representing the certificate to use
        logger -- The logger object to use for logging
        """

        # Perform a request to the URL and see what authentication method is required
        try:

            # Make the GET
            http = requests.get(url.geturl(), proxies=proxies, timeout=timeout, cert=cert,
                                verify=False)

            # Find the authentication header irrespective of case
            auth_header_value = None

            for header, value in http.headers.items():
                if header.lower() == 'www-authenticate':
                    auth_header_value = value
                    break

            # Determine if the authentication header is present and use it to determine the
            # authentication type
            if auth_header_value is not None:

                # Handle the pesky cases where a comma separated value is provided in the header
                # for NTLM negotiation (like "negotiate, ntlm")
                if 'ntlm' in auth_header_value.lower():
                    return cls.HTTP_AUTH_NTLM

                # Otherwise, check the HTTP header for the authentication header
                m = re.search('^([a-zA-Z0-9]+)', auth_header_value)
                auth_type = m.group(1)
                return auth_type.lower()

            # No authentication header is present
            else:
                if logger:
                    logger.warn("Unable to determine authentication type (no www-authenticate header); will default to basic authentication")

                return cls.HTTP_AUTH_NONE

        except Exception:

            if logger:
                logger.exception("Unable to determine authentication type")
Example #5
0
    def ping(cls,
             url,
             username=None,
             password=None,
             timeout=30,
             proxy_type=None,
             proxy_server=None,
             proxy_port=None,
             proxy_user=None,
             proxy_password=None,
             client_certificate=None,
             client_certificate_key=None,
             user_agent=None,
             logger=None,
             should_contain_string=None):
        """
        Perform a ping to a website. Returns a WebPing.Result instance.

        Argument:
        url -- The url to connect to. This object ought to be an instance derived from using urlparse.
        username -- The password to use for authentication
        password -- The username to use for authentication
        timeout -- The amount of time to quit waiting on a connection.
        proxy_type -- The type of the proxy server (must be one of: socks4, socks5, http)
        proxy_server -- The proxy server to use.
        proxy_port -- The port on the proxy server to use.
        proxy_user -- The proxy server to use.
        proxy_password -- The port on the proxy server to use.
        client_certificate -- The path to the client certificate to use.
        client_certificate_key -- The path to the client key to use.
        user_agent -- The string to use for the user-agent
        logger -- The logger object to use for logging
        should_contain_string -- A string that is expected in the response
        """

        if logger:
            logger.info('Performing ping, url="%s"', url.geturl())

        # Determine which type of proxy is to be used (if any)
        resolved_proxy_type = cls.resolve_proxy_type(proxy_type, logger=logger)

        # Set should_contain_string to none if it is blank since this means it really doesn't have
        # a value
        if should_contain_string is not None and len(
                should_contain_string.strip()) == 0:
            should_contain_string = None

        # Make sure that a timeout is not None since that is infinite
        if timeout is None:
            timeout = 30

        # Setup the proxy info if so configured
        proxies = {}

        if resolved_proxy_type is not None and proxy_server is not None and len(
                proxy_server.strip()) > 0:

            if proxy_type == "http":

                # Use the username and password if provided
                if proxy_password is not None and proxy_user is not None:
                    proxies = {
                        "http":
                        "http://" + proxy_user + ":" + proxy_password + "@" +
                        proxy_server + ":" + str(proxy_port),
                        "https":
                        "http://" + proxy_user + ":" + proxy_password + "@" +
                        proxy_server + ":" + str(proxy_port)
                    }
                else:
                    proxies = {
                        "http":
                        "http://" + proxy_server + ":" + str(proxy_port),
                        "https":
                        "http://" + proxy_server + ":" + str(proxy_port)
                    }

            else:
                socks.setdefaultproxy(resolved_proxy_type, proxy_server,
                                      proxy_port)
                socket.socket = socks.socksocket

        else:
            # No proxy is being used
            pass

        # Setup the client certificate parameter
        if client_certificate is not None and client_certificate_key is not None:
            cert = (client_certificate, client_certificate_key)
        elif client_certificate is not None:
            cert = client_certificate
        else:
            cert = None

        if logger and cert is not None:
            logger.debug("Using client certificate %s", cert)

        request_time = 0
        response_code = 0
        response_md5 = None
        response_sha224 = None
        timed_out = False
        response_size = None
        has_expected_string = None

        # Setup the headers as necessary
        headers = {}

        if user_agent is not None:
            if logger:
                logger.debug("Setting user-agent=%s", user_agent)

            headers['User-Agent'] = user_agent

        # Make an auth object if necessary
        auth = None
        auth_type = None

        if username is not None and password is not None:

            # Determine the auth type
            auth_type = cls.determine_auth_type(url,
                                                proxies=proxies,
                                                timeout=timeout,
                                                cert=cert,
                                                logger=logger)

            # Don't allow the use of NTLM on a host in FIPS mode since NTLM uses MD4 which is a
            # weak algorithm
            if auth_type == cls.HTTP_AUTH_NTLM and cls.is_fips_mode():

                if logger:
                    logger.warn(
                        "Authentication type was automatically identified but will not be used since it uses a weak hash algorithm which is not allowed on this host since it is running in FIPS mode; auth_type=%s",
                        auth_type)

                auth_type = cls.HTTP_AUTH_NONE

            # The authentication type could not be determined. However, we know that
            # authentication is required since a username and password was provided.
            # Default to HTTP basic authentication.
            elif auth_type == cls.HTTP_AUTH_NONE:
                auth_type = cls.HTTP_AUTH_BASIC

                if logger:
                    logger.info(
                        "Authentication type could not be automatically discovered; auth_type=%s",
                        auth_type)

            elif logger is not None:
                logger.debug("Discovered auth_type=%s", auth_type)

            # Get the authentication class for request
            auth = cls.create_auth_for_request(auth_type, username, password,
                                               logger)

        try:

            # Perform the request
            with Timer() as timer:

                # Make the client
                http = requests.get(url.geturl(),
                                    proxies=proxies,
                                    timeout=timeout,
                                    cert=cert,
                                    verify=False,
                                    auth=auth,
                                    headers=headers)

                # Get the hash of the content
                if not cls.is_fips_mode():
                    response_md5 = hashlib.md5(http.text).hexdigest()

                response_sha224 = hashlib.sha224(http.text).hexdigest()

                # Determine if the expected string is in the content
                if should_contain_string is not None:
                    has_expected_string = should_contain_string in http.text

                # Get the size of the content
                response_size = len(http.text)

            response_code = http.status_code
            request_time = timer.msecs

        # Handle time outs
        except requests.exceptions.Timeout:

            # Note that the connection timed out
            timed_out = True

        except requests.exceptions.SSLError as e:

            if logger:
                logger.error(
                    "An SSL exception was thrown when executing a web request against url=%s: "
                    + str(e), url.geturl())

        except requests.exceptions.ConnectionError as e:

            if e.args is not None and len(e.args) > 0 and hasattr(
                    e.args[0], 'reason') and hasattr(
                        e.args[0].reason,
                        'errno') and e.args[0].reason.errno in [
                            60, 61, 10060, 10061
                        ]:
                timed_out = True

            elif logger:
                logger.exception(
                    "A connection exception was thrown when executing a web request against url=%s, this can happen if the domain name, IP address is invalid or if network connectivity is down or blocked by a firewall; see help_url=http://lukemurphey.net/projects/splunk-website-monitoring/wiki/Troubleshooting",
                    url.geturl())

        except socks.GeneralProxyError:
            # This may be thrown if the user configured the proxy settings incorrectly
            if logger:
                logger.exception(
                    "An error occurred when attempting to communicate with the proxy for url=%s",
                    url.geturl())

        except Exception as e:
            if logger:
                logger.exception(
                    "A general exception was thrown when executing a web request for url=%s",
                    url.geturl())

        # Finally, return the result
        return cls.Result(request_time, response_code, timed_out, url.geturl(),
                          response_size, response_md5, response_sha224,
                          has_expected_string)
    def ping(cls, url, username=None, password=None, timeout=30, proxy_type=None,
             proxy_server=None, proxy_port=None, proxy_user=None, proxy_password=None, proxy_ignore=None,
             client_certificate=None, client_certificate_key=None, user_agent=None,
             logger=None, should_contain_string=None):
        """
        Perform a ping to a website. Returns a WebPing.Result instance.

        Argument:
        url -- The url to connect to. This object ought to be an instance derived from using urlparse.
        username -- The password to use for authentication
        password -- The username to use for authentication
        timeout -- The amount of time to quit waiting on a connection.
        proxy_type -- The type of the proxy server (must be one of: socks4, socks5, http)
        proxy_server -- The proxy server to use.
        proxy_port -- The port on the proxy server to use.
        proxy_user -- The proxy server to use.
        proxy_password -- The port on the proxy server to use.
        proxy_ignore -- The list of domains to not use the proxy server for.
        client_certificate -- The path to the client certificate to use.
        client_certificate_key -- The path to the client key to use.
        user_agent -- The string to use for the user-agent
        logger -- The logger object to use for logging
        should_contain_string -- A string that is expected in the response
        """

        if logger:
            logger.info('Performing ping, url="%s"', url.geturl())
    
        # Disable the use of the proxy variables
        if proxy_ignore is not None:
            os.environ['NO_PROXY'] = proxy_ignore

        if logger:
            logger.debug('Proxies discovered from the environment, proxies="%r"', urllib.getproxies())

        # Determine which type of proxy is to be used (if any)
        resolved_proxy_type = cls.resolve_proxy_type(proxy_type, logger=logger)

        # Set should_contain_string to none if it is blank since this means it really doesn't have
        # a value
        if should_contain_string is not None and len(should_contain_string.strip()) == 0:
            should_contain_string = None

        # Make sure that a timeout is not None since that is infinite
        if timeout is None:
            timeout = 30

        # Setup the proxy info if so configured
        proxies = {}

        if resolved_proxy_type is not None and proxy_server is not None and len(proxy_server.strip()) > 0:

            if proxy_type == "http":

                # Use the username and password if provided
                if proxy_password is not None and proxy_user is not None:
                    proxies = {
                        "http": "http://" + proxy_user + ":" + proxy_password + "@" + proxy_server + ":" + str(proxy_port),
                        "https": "http://" + proxy_user + ":" + proxy_password + "@" + proxy_server + ":" + str(proxy_port)
                    }
                else:
                    proxies = {
                        "http": "http://" + proxy_server + ":" + str(proxy_port),
                        "https": "http://" + proxy_server + ":" + str(proxy_port)
                    }

            else:
                socks.setdefaultproxy(resolved_proxy_type, proxy_server, int(proxy_port))
                socket.socket = socks.socksocket
                if logger:
                    logger.debug("Using socks proxy server=%s, port=%s", proxy_server, proxy_port)

        else:
            # No proxy is being used
            pass

        # Setup the client certificate parameter
        if client_certificate is not None and client_certificate_key is not None:
            cert = (client_certificate, client_certificate_key)
        elif client_certificate is not None:
            cert = client_certificate
        else:
            cert = None

        if logger and cert is not None:
            logger.debug("Using client certificate %s", cert)

        request_time = 0
        response_code = 0
        response_md5 = None
        response_sha224 = None
        timed_out = False
        response_size = None
        has_expected_string = None

        # Setup the headers as necessary
        headers = {}

        if user_agent is not None:
            if logger:
                logger.debug("Setting user-agent=%s", user_agent)

            headers['User-Agent'] = user_agent

        # Make an auth object if necessary
        auth = None
        auth_type = None

        if username is not None and password is not None:

            # Determine the auth type
            auth_type = cls.determine_auth_type(url, proxies=proxies, timeout=timeout, cert=cert,
                                                logger=logger)

            # Don't allow the use of NTLM on a host in FIPS mode since NTLM uses MD4 which is a
            # weak algorithm
            if auth_type == cls.HTTP_AUTH_NTLM and cls.is_fips_mode():

                if logger:
                    logger.warn("Authentication type was automatically identified but will not be used since it uses a weak hash algorithm which is not allowed on this host since it is running in FIPS mode; auth_type=%s", auth_type)

                auth_type = cls.HTTP_AUTH_NONE

            # The authentication type could not be determined. However, we know that
            # authentication is required since a username and password was provided.
            # Default to HTTP basic authentication.
            elif auth_type == cls.HTTP_AUTH_NONE:
                auth_type = cls.HTTP_AUTH_BASIC

                if logger:
                    logger.info("Authentication type could not be automatically discovered; auth_type=%s", auth_type)

            elif logger is not None:
                logger.debug("Discovered auth_type=%s", auth_type)

            # Get the authentication class for request
            auth = cls.create_auth_for_request(auth_type, username, password, logger)

        try:

            # Perform the request
            with Timer() as timer:

                # Make the client
                http = requests.get(url.geturl(), proxies=proxies, timeout=timeout, cert=cert, verify=False, auth=auth, headers=headers)

                # Get the hash of the content
                if not cls.is_fips_mode():
                    response_md5 = hashlib.md5(http.text).hexdigest()

                response_sha224 = hashlib.sha224(http.text).hexdigest()

                # Determine if the expected string is in the content
                if should_contain_string is not None:
                    has_expected_string = should_contain_string in http.text

                # Get the size of the content
                response_size = len(http.text)

            response_code = http.status_code
            request_time = timer.msecs

        # Handle time outs
        except requests.exceptions.Timeout:
            # Note that the connection timed out
            timed_out = True

        except requests.exceptions.SSLError as e:
            if logger:
                logger.error("An SSL exception was thrown when executing a web request against url=%s: " + str(e), url.geturl())

        except requests.exceptions.ConnectionError as e:
            timed_out = WebPing.isExceptionForTimeout(e)

            if not timed_out and logger:
                logger.exception("A connection exception was thrown when executing a web request against url=%s, this can happen if the domain name, IP address is invalid or if network connectivity is down or blocked by a firewall; see help_url=http://lukemurphey.net/projects/splunk-website-monitoring/wiki/Troubleshooting", url.geturl())

        except socks.GeneralProxyError:
            # This may be thrown if the user configured the proxy settings incorrectly
            if logger:
                logger.exception("An error occurred when attempting to communicate with the proxy for url=%s", url.geturl())

        except Exception as e:
            if logger:
                logger.exception("A general exception was thrown when executing a web request for url=%s", url.geturl())

        # Finally, return the result
        return cls.Result(request_time, response_code, timed_out, url.geturl(), response_size, response_md5, response_sha224, has_expected_string)
 def ping(cls, url, timeout=30, proxy_type=None, proxy_server=None, proxy_port=None, proxy_user=None, proxy_password=None, client_certificate=None, client_certificate_key=None, logger=None):
     """
     Perform a ping to a website. Returns a WebPing.Result instance.
     
     Argument:
     url -- The url to connect to. This object ought to be an instance derived from using urlparse.
     timeout -- The amount of time to quit waiting on a connection.
     proxy_type -- The type of the proxy server (must be one of: socks4, socks5, http)
     proxy_server -- The proxy server to use.
     proxy_port -- The port on the proxy server to use.
     proxy_user -- The proxy server to use.
     proxy_password -- The port on the proxy server to use.
     client_certificate -- The path to the client certificate to use.
     client_certificate_key -- The path to the client key to use.
     logger -- The logger object to use for logging
     """
     
     if logger:
         logger.debug('Performing ping, url="%s"', url.geturl())
     
     # Determine which type of proxy is to be used (if any)
     resolved_proxy_type = cls.resolve_proxy_type(proxy_type, logger=logger)
     
     # Make sure that a timeout is not None since that is infinite
     if timeout is None:
         timeout = 30
     
     # Setup the proxy info if so configured
     proxies = {}
     
     if resolved_proxy_type is not None and proxy_server is not None and len(proxy_server.strip()) > 0:
         
         if proxy_type == "http":
             
             # Use the username and password if provided
             if proxy_password is not None and proxy_user is not None:
                 proxies = {
                   "http": "http://" + proxy_user + ":" + proxy_password + "@" + proxy_server + ":" + str(proxy_port),
                   "https": "http://" + proxy_user + ":" + proxy_password + "@" + proxy_server + ":" + str(proxy_port)
                 }
             else:
                 proxies = {
                   "http": "http://" + proxy_server + ":" + str(proxy_port),
                   "https": "http://" + proxy_server + ":" + str(proxy_port)
                 }
             
         else:
             socks.setdefaultproxy(resolved_proxy_type, proxy_server, proxy_port)
             socket.socket = socks.socksocket
         
     else:
         # No proxy is being used
         pass
     
     # Setup the client certificate parameter
     if client_certificate is not None and client_certificate_key is not None:
         cert = (client_certificate, client_certificate_key)
     elif client_certificate is not None:
         cert = client_certificate
     else:
         cert = None
         
     if logger:
         logger.debug("Using client certificate %s", cert)
     
     request_time    = 0
     response_code   = 0
     response_md5    = None
     response_sha224 = None
     timed_out       = False
     response_size   = None
     
     try:
         
         # Perform the request
         with Timer() as timer:
             
             # Make the client
             http = requests.get(url.geturl(), proxies=proxies, timeout=timeout, cert=cert)
             
             # Get the hash of the content
             response_md5 = hashlib.md5(http.text).hexdigest()
             response_sha224 = hashlib.sha224(http.text).hexdigest()
             
             # Get the size of the content
             response_size = len(http.text)
             
         response_code = http.status_code    
         request_time = timer.msecs
         
     # Handle time outs    
     except requests.exceptions.Timeout:
         
         # Note that the connection timed out
         timed_out = True
         
     except requests.exceptions.ConnectionError as e:
         
         if e.args is not None and len(e.args) > 0 and hasattr(e.args[0], 'reason') and hasattr(e.args[0].reason, 'errno') and e.args[0].reason.errno in [60, 61]:
             timed_out = True
             
         elif logger:
             logger.exception("A connection exception was thrown when executing a web request")
             
     except socks.GeneralProxyError:
         # This may be thrown if the user configured the proxy settings incorrectly
         if logger:
             logger.exception("An error occurred when attempting to communicate with the proxy")
     
     except Exception as e:
         if logger:
             logger.exception("A general exception was thrown when executing a web request")
         
     # Finally, return the result
     return cls.Result(request_time, response_code, timed_out, url.geturl(), response_size, response_md5, response_sha224)
 def ping(cls, url, username=None, password=None, timeout=30, proxy_type=None, proxy_server=None, proxy_port=None, proxy_user=None, proxy_password=None, client_certificate=None, client_certificate_key=None, logger=None):
     """
     Perform a ping to a website. Returns a WebPing.Result instance.
     
     Argument:
     url -- The url to connect to. This object ought to be an instance derived from using urlparse.
     username -- The password to use for authentication
     password -- The username to use for authentication
     timeout -- The amount of time to quit waiting on a connection.
     proxy_type -- The type of the proxy server (must be one of: socks4, socks5, http)
     proxy_server -- The proxy server to use.
     proxy_port -- The port on the proxy server to use.
     proxy_user -- The proxy server to use.
     proxy_password -- The port on the proxy server to use.
     client_certificate -- The path to the client certificate to use.
     client_certificate_key -- The path to the client key to use.
     logger -- The logger object to use for logging
     """
     
     if logger:
         logger.info('Performing ping, url="%s"', url.geturl())
     
     # Determine which type of proxy is to be used (if any)
     resolved_proxy_type = cls.resolve_proxy_type(proxy_type, logger=logger)
     
     # Make sure that a timeout is not None since that is infinite
     if timeout is None:
         timeout = 30
     
     # Setup the proxy info if so configured
     proxies = {}
     
     if resolved_proxy_type is not None and proxy_server is not None and len(proxy_server.strip()) > 0:
         
         if proxy_type == "http":
             
             # Use the username and password if provided
             if proxy_password is not None and proxy_user is not None:
                 proxies = {
                   "http": "http://" + proxy_user + ":" + proxy_password + "@" + proxy_server + ":" + str(proxy_port),
                   "https": "http://" + proxy_user + ":" + proxy_password + "@" + proxy_server + ":" + str(proxy_port)
                 }
             else:
                 proxies = {
                   "http": "http://" + proxy_server + ":" + str(proxy_port),
                   "https": "http://" + proxy_server + ":" + str(proxy_port)
                 }
             
         else:
             socks.setdefaultproxy(resolved_proxy_type, proxy_server, proxy_port)
             socket.socket = socks.socksocket
         
     else:
         # No proxy is being used
         pass
     
     # Setup the client certificate parameter
     if client_certificate is not None and client_certificate_key is not None:
         cert = (client_certificate, client_certificate_key)
     elif client_certificate is not None:
         cert = client_certificate
     else:
         cert = None
         
     if logger:
         logger.debug("Using client certificate %s", cert)
     
     request_time    = 0
     response_code   = 0
     response_md5    = None
     response_sha224 = None
     timed_out       = False
     response_size   = None
     
     # Make an auth object if necessary
     auth = None
     auth_type = None
     
     if username is not None and password is not None:
         
         # Determine the auth type
         auth_type = cls.determine_auth_type(url, proxies=proxies, timeout=timeout, cert=cert, logger=logger)
     
         # Get the authentication class for request
         auth = cls.create_auth_for_request(auth_type, username, password, logger)
         
         if logger is not None:
             logger.debug("Discovered auth_type=%s", auth_type)
     
     try:
         
         # Perform the request
         with Timer() as timer:
             
             # Make the client
             http = requests.get(url.geturl(), proxies=proxies, timeout=timeout, cert=cert, verify=False, auth=auth)
             
             # Get the hash of the content
             response_md5 = hashlib.md5(http.text).hexdigest()
             response_sha224 = hashlib.sha224(http.text).hexdigest()
             
             # Get the size of the content
             response_size = len(http.text)
             
         response_code = http.status_code    
         request_time = timer.msecs
         
     # Handle time outs
     except requests.exceptions.Timeout:
         
         # Note that the connection timed out
         timed_out = True
         
     except requests.exceptions.SSLError as e:
         
         if logger:
             logger.error("An SSL exception was thrown when executing a web request: " + str(e))
         
     except requests.exceptions.ConnectionError as e:
         
         if e.args is not None and len(e.args) > 0 and hasattr(e.args[0], 'reason') and hasattr(e.args[0].reason, 'errno') and e.args[0].reason.errno in [60, 61]:
             timed_out = True
             
         elif logger:
             logger.exception("A connection exception was thrown when executing a web request")
             
     except socks.GeneralProxyError:
         # This may be thrown if the user configured the proxy settings incorrectly
         if logger:
             logger.exception("An error occurred when attempting to communicate with the proxy")
     
     except Exception as e:
         if logger:
             logger.exception("A general exception was thrown when executing a web request")
         
     # Finally, return the result
     return cls.Result(request_time, response_code, timed_out, url.geturl(), response_size, response_md5, response_sha224)