Top

qcloudsms_py.httpclient module

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import absolute_import, division, print_function

import re
import json
import sys
import socket

if sys.version_info >= (3,):
    from http import client as httplib
    from urllib import parse as urlparse
else:
    import httplib
    import urlparse


class HTTPRequest(object):

     def __init__(self, url, method="GET", headers=None, body=None):
         """
         :param url: HTTP request URL.
         :param method:  (optiona) HTTP method.
         :param headers: (optional) Dictionary for HTTP request headers.
         :param body: (optional) Dictionary for HTTP request body.
         :param connect_timeout: (optional) HTTP connection timeout.
         :param request_timeout: (optional) HTTP request timeout.
         """
         self.url = url
         self.method = method
         self.headers = headers
         self.body = body


class HTTPResponse(object):

    def __init__(self, request, code, body,
                 headers=None, reason=None):
        """
         :param request: HTTPRequest instance.
         :param code:  HTTP status code.
         :param body: Raw bytes of HTTP response body.
         :param headers: (optional) Dictionary for HTTP response headers.
         :param reason: (optional) HTTP status reason.
         """
        self.request = request
        self.code = code
        self.body = body
        self.headers = headers
        self.reason = reason or httplib.responses.get(code, "Unknown")

    def ok(self):
        if self.code == 200 or self.code == "200":
            return True
        return False

    def json(self):
        if sys.version_info >= (3, ) and sys.version_info < (3, 6):
            return json.loads(self.body.decode("utf-8"),
                              encoding="utf=8")
        return json.loads(self.body, encoding="utf-8")


class HTTPError(Exception):

    def __init__(self, code, reason=None):
        self.code = code
        self.reason = reason or httplib.responses.get(code, "Unknown")
        super(HTTPError, self).__init__(code, reason)

    def __str__(self):
        return "HTTP {}: {}".format(self.code, self.reason)
    __repr__ = __str__


if sys.version_info >= (3,):
    unicode_type = str
else:
    unicode_type = unicode


def utf8(value):
    """Converts a string argument to a byte string.

    If the argument is already a byte string or None, it is returned
    unchanged. Otherwise it must be a unicode string and is encoded
    as utf8.

    NOTE: This method copy from https://github.com/tornadoweb/tornado and
          copyright belongs to the original author.
    """
    if isinstance(value, (bytes, type(None))):
        return value
    if not isinstance(value, unicode_type):
        raise TypeError(
            "Expected bytes, unicode, or None; got %r" % type(value)
        )
    return value.encode("utf-8")


class HTTPClientInterface(object):

    def fetch(self, req):
        raise NotImplementedError


class HTTPSimpleClient(HTTPClientInterface):

    PATTERN = "(?:http.*://)?(?P<host>[^:/ ]+).?(?P<port>[0-9]*).*"

    def __init__(self, connect_timeout=60, request_timeout=60,
                 proxy=None):
        self._connect_timeout = connect_timeout
        self._request_timeout = request_timeout
        if isinstance(proxy, (list, tuple)):
            self._proxy = (proxy[0], int(proxy[1]))
        elif isinstance(proxy, (bytes, unicode_type)):
            proxy = utf8(proxy)
            result = re.search(self.__class__.PATTERN, proxy)
            if not result:
                raise ValueError("invalid proxy")
            self._proxy = (
                result.group("host"),
                int(result.group("port")) if result.group("port") else 80
            )
        elif proxy is None:
            self._proxy = None
        else:
            raise ValueError("invalid proxy")

    def fetch(self, req):
        result = urlparse.urlparse(req.url)
        if self._proxy:
            host, port = self._proxy
        else:
            host, port = (result.hostname, result.port)

        if result.scheme == "https":
            conn = httplib.HTTPSConnection(
                host,
                port=port,
                timeout=self._connect_timeout
            )
        else:
            conn = httplib.HTTPConnection(
                host,
                port=port,
                timeout=self._connect_timeout
            )

        if self._proxy:
            conn.set_tunnel(result.hostname, result.port)

        # Send request
        try:
            conn.request(
                req.method,
                "{}?{}".format(result.path, result.query),
                body=utf8(req.body),
                headers=req.headers
            )
            response = conn.getresponse()
            res = HTTPResponse(
                request=req,
                code=response.status,
                body=response.read(),
                headers=dict(response.getheaders()),
                reason=response.reason
            )
        except socket.gaierror:
            # client network error, raise
            raise
        except OSError:
            # client network error, raise
            raise
        finally:
            conn.close()
        return res

Functions

def utf8(

value)

Converts a string argument to a byte string.

If the argument is already a byte string or None, it is returned unchanged. Otherwise it must be a unicode string and is encoded as utf8.

NOTE: This method copy from https://github.com/tornadoweb/tornado and copyright belongs to the original author.

def utf8(value):
    """Converts a string argument to a byte string.

    If the argument is already a byte string or None, it is returned
    unchanged. Otherwise it must be a unicode string and is encoded
    as utf8.

    NOTE: This method copy from https://github.com/tornadoweb/tornado and
          copyright belongs to the original author.
    """
    if isinstance(value, (bytes, type(None))):
        return value
    if not isinstance(value, unicode_type):
        raise TypeError(
            "Expected bytes, unicode, or None; got %r" % type(value)
        )
    return value.encode("utf-8")

Classes

class HTTPClientInterface

class HTTPClientInterface(object):

    def fetch(self, req):
        raise NotImplementedError

Ancestors (in MRO)

Methods

def fetch(

self, req)

def fetch(self, req):
    raise NotImplementedError

class HTTPError

class HTTPError(Exception):

    def __init__(self, code, reason=None):
        self.code = code
        self.reason = reason or httplib.responses.get(code, "Unknown")
        super(HTTPError, self).__init__(code, reason)

    def __str__(self):
        return "HTTP {}: {}".format(self.code, self.reason)
    __repr__ = __str__

Ancestors (in MRO)

Class variables

var args

var message

Instance variables

var code

var reason

Methods

def __init__(

self, code, reason=None)

def __init__(self, code, reason=None):
    self.code = code
    self.reason = reason or httplib.responses.get(code, "Unknown")
    super(HTTPError, self).__init__(code, reason)

class HTTPRequest

class HTTPRequest(object):

     def __init__(self, url, method="GET", headers=None, body=None):
         """
         :param url: HTTP request URL.
         :param method:  (optiona) HTTP method.
         :param headers: (optional) Dictionary for HTTP request headers.
         :param body: (optional) Dictionary for HTTP request body.
         :param connect_timeout: (optional) HTTP connection timeout.
         :param request_timeout: (optional) HTTP request timeout.
         """
         self.url = url
         self.method = method
         self.headers = headers
         self.body = body

Ancestors (in MRO)

Instance variables

var body

var headers

var method

var url

Methods

def __init__(

self, url, method='GET', headers=None, body=None)

:param url: HTTP request URL. :param method: (optiona) HTTP method. :param headers: (optional) Dictionary for HTTP request headers. :param body: (optional) Dictionary for HTTP request body. :param connect_timeout: (optional) HTTP connection timeout. :param request_timeout: (optional) HTTP request timeout.

def __init__(self, url, method="GET", headers=None, body=None):
    """
    :param url: HTTP request URL.
    :param method:  (optiona) HTTP method.
    :param headers: (optional) Dictionary for HTTP request headers.
    :param body: (optional) Dictionary for HTTP request body.
    :param connect_timeout: (optional) HTTP connection timeout.
    :param request_timeout: (optional) HTTP request timeout.
    """
    self.url = url
    self.method = method
    self.headers = headers
    self.body = body

class HTTPResponse

class HTTPResponse(object):

    def __init__(self, request, code, body,
                 headers=None, reason=None):
        """
         :param request: HTTPRequest instance.
         :param code:  HTTP status code.
         :param body: Raw bytes of HTTP response body.
         :param headers: (optional) Dictionary for HTTP response headers.
         :param reason: (optional) HTTP status reason.
         """
        self.request = request
        self.code = code
        self.body = body
        self.headers = headers
        self.reason = reason or httplib.responses.get(code, "Unknown")

    def ok(self):
        if self.code == 200 or self.code == "200":
            return True
        return False

    def json(self):
        if sys.version_info >= (3, ) and sys.version_info < (3, 6):
            return json.loads(self.body.decode("utf-8"),
                              encoding="utf=8")
        return json.loads(self.body, encoding="utf-8")

Ancestors (in MRO)

Instance variables

var body

var code

var headers

var reason

var request

Methods

def __init__(

self, request, code, body, headers=None, reason=None)

:param request: HTTPRequest instance. :param code: HTTP status code. :param body: Raw bytes of HTTP response body. :param headers: (optional) Dictionary for HTTP response headers. :param reason: (optional) HTTP status reason.

def __init__(self, request, code, body,
             headers=None, reason=None):
    """
     :param request: HTTPRequest instance.
     :param code:  HTTP status code.
     :param body: Raw bytes of HTTP response body.
     :param headers: (optional) Dictionary for HTTP response headers.
     :param reason: (optional) HTTP status reason.
     """
    self.request = request
    self.code = code
    self.body = body
    self.headers = headers
    self.reason = reason or httplib.responses.get(code, "Unknown")

def json(

self)

def json(self):
    if sys.version_info >= (3, ) and sys.version_info < (3, 6):
        return json.loads(self.body.decode("utf-8"),
                          encoding="utf=8")
    return json.loads(self.body, encoding="utf-8")

def ok(

self)

def ok(self):
    if self.code == 200 or self.code == "200":
        return True
    return False

class HTTPSimpleClient

class HTTPSimpleClient(HTTPClientInterface):

    PATTERN = "(?:http.*://)?(?P<host>[^:/ ]+).?(?P<port>[0-9]*).*"

    def __init__(self, connect_timeout=60, request_timeout=60,
                 proxy=None):
        self._connect_timeout = connect_timeout
        self._request_timeout = request_timeout
        if isinstance(proxy, (list, tuple)):
            self._proxy = (proxy[0], int(proxy[1]))
        elif isinstance(proxy, (bytes, unicode_type)):
            proxy = utf8(proxy)
            result = re.search(self.__class__.PATTERN, proxy)
            if not result:
                raise ValueError("invalid proxy")
            self._proxy = (
                result.group("host"),
                int(result.group("port")) if result.group("port") else 80
            )
        elif proxy is None:
            self._proxy = None
        else:
            raise ValueError("invalid proxy")

    def fetch(self, req):
        result = urlparse.urlparse(req.url)
        if self._proxy:
            host, port = self._proxy
        else:
            host, port = (result.hostname, result.port)

        if result.scheme == "https":
            conn = httplib.HTTPSConnection(
                host,
                port=port,
                timeout=self._connect_timeout
            )
        else:
            conn = httplib.HTTPConnection(
                host,
                port=port,
                timeout=self._connect_timeout
            )

        if self._proxy:
            conn.set_tunnel(result.hostname, result.port)

        # Send request
        try:
            conn.request(
                req.method,
                "{}?{}".format(result.path, result.query),
                body=utf8(req.body),
                headers=req.headers
            )
            response = conn.getresponse()
            res = HTTPResponse(
                request=req,
                code=response.status,
                body=response.read(),
                headers=dict(response.getheaders()),
                reason=response.reason
            )
        except socket.gaierror:
            # client network error, raise
            raise
        except OSError:
            # client network error, raise
            raise
        finally:
            conn.close()
        return res

Ancestors (in MRO)

Class variables

var PATTERN

Methods

def __init__(

self, connect_timeout=60, request_timeout=60, proxy=None)

def __init__(self, connect_timeout=60, request_timeout=60,
             proxy=None):
    self._connect_timeout = connect_timeout
    self._request_timeout = request_timeout
    if isinstance(proxy, (list, tuple)):
        self._proxy = (proxy[0], int(proxy[1]))
    elif isinstance(proxy, (bytes, unicode_type)):
        proxy = utf8(proxy)
        result = re.search(self.__class__.PATTERN, proxy)
        if not result:
            raise ValueError("invalid proxy")
        self._proxy = (
            result.group("host"),
            int(result.group("port")) if result.group("port") else 80
        )
    elif proxy is None:
        self._proxy = None
    else:
        raise ValueError("invalid proxy")

def fetch(

self, req)

Inheritance: HTTPClientInterface.fetch

def fetch(self, req):
    result = urlparse.urlparse(req.url)
    if self._proxy:
        host, port = self._proxy
    else:
        host, port = (result.hostname, result.port)
    if result.scheme == "https":
        conn = httplib.HTTPSConnection(
            host,
            port=port,
            timeout=self._connect_timeout
        )
    else:
        conn = httplib.HTTPConnection(
            host,
            port=port,
            timeout=self._connect_timeout
        )
    if self._proxy:
        conn.set_tunnel(result.hostname, result.port)
    # Send request
    try:
        conn.request(
            req.method,
            "{}?{}".format(result.path, result.query),
            body=utf8(req.body),
            headers=req.headers
        )
        response = conn.getresponse()
        res = HTTPResponse(
            request=req,
            code=response.status,
            body=response.read(),
            headers=dict(response.getheaders()),
            reason=response.reason
        )
    except socket.gaierror:
        # client network error, raise
        raise
    except OSError:
        # client network error, raise
        raise
    finally:
        conn.close()
    return res