139 lines
5.0 KiB
Python
139 lines
5.0 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import socket
|
|
try:
|
|
from http.client import HTTPConnection, BadStatusLine, HTTPSConnection
|
|
from urllib.parse import urlparse
|
|
except ImportError:
|
|
from httplib import HTTPConnection, BadStatusLine, HTTPSConnection
|
|
from urlparse import urlparse
|
|
|
|
from .api_exception import ApiClientNetworkException, ApiClientParamException
|
|
|
|
|
|
class MyHTTPSConnection(HTTPSConnection):
|
|
def __init__(self, host, port=None):
|
|
self.has_proxy = False
|
|
self.request_host = host
|
|
https_proxy = (os.environ.get('https_proxy')
|
|
or os.environ.get('HTTPS_PROXY'))
|
|
if https_proxy:
|
|
url = urlparse(https_proxy)
|
|
if not url.hostname:
|
|
url = urlparse('https://' + https_proxy)
|
|
host = url.hostname
|
|
port = url.port
|
|
self.has_proxy = True
|
|
HTTPSConnection.__init__(self, host, port)
|
|
self.request_length = 0
|
|
|
|
def send(self, astr):
|
|
HTTPSConnection.send(self, astr)
|
|
self.request_length += len(astr)
|
|
|
|
def request(self, method, url, body=None, headers={}):
|
|
self.request_length = 0
|
|
if self.has_proxy:
|
|
self.set_tunnel(self.request_host, 443)
|
|
HTTPSConnection.request(self, method, url, body, headers)
|
|
|
|
|
|
class ApiRequest(object):
|
|
def __init__(self, host, req_timeout=90, debug=False):
|
|
self.conn = MyHTTPSConnection(host)
|
|
self.req_timeout = req_timeout
|
|
self.keep_alive = False
|
|
self.debug = debug
|
|
self.request_size = 0
|
|
self.response_size = 0
|
|
|
|
def set_req_timeout(self, req_timeout):
|
|
self.req_timeout = req_timeout
|
|
|
|
def is_keep_alive(self):
|
|
return self.keep_alive
|
|
|
|
def set_debug(self, debug):
|
|
self.debug = debug
|
|
|
|
def send_request(self, req_inter):
|
|
try:
|
|
if self.debug:
|
|
print("SendRequest %s" % req_inter)
|
|
if req_inter.method == 'GET':
|
|
req_inter_url = '%s?%s' % (req_inter.uri, req_inter.data)
|
|
self.conn.request(req_inter.method, req_inter_url,
|
|
None, req_inter.header)
|
|
elif req_inter.method == 'POST':
|
|
self.conn.request(req_inter.method, req_inter.uri,
|
|
req_inter.data, req_inter.header)
|
|
else:
|
|
raise ApiClientParamException(
|
|
'Method only support (GET, POST)')
|
|
|
|
self.conn.sock.settimeout(self.req_timeout)
|
|
self.conn.sock.setsockopt(socket.IPPROTO_TCP,
|
|
socket.TCP_NODELAY, 1)
|
|
try:
|
|
http_resp = self.conn.getresponse()
|
|
except BadStatusLine:
|
|
# open another connection when keep-alive timeout
|
|
# httplib will not handle keep-alive timeout,
|
|
# so we must handle it ourself
|
|
if self.debug:
|
|
print("keep-alive timeout, reopen connection")
|
|
self.conn.close()
|
|
|
|
self.conn.request(req_inter.method, req_inter.uri,
|
|
req_inter.data, req_inter.header)
|
|
self.conn.sock.settimeout(self.req_timeout)
|
|
self.conn.sock.setsockopt(socket.IPPROTO_TCP,
|
|
socket.TCP_NODELAY, 1)
|
|
http_resp = self.conn.getresponse()
|
|
headers = dict(http_resp.getheaders())
|
|
resp_inter = ResponseInternal(status=http_resp.status,
|
|
header=headers,
|
|
data=http_resp.read())
|
|
self.request_size = self.conn.request_length
|
|
self.response_size = len(resp_inter.data)
|
|
if not self.is_keep_alive():
|
|
self.conn.close()
|
|
if self.debug:
|
|
print(("GetResponse %s" % resp_inter))
|
|
return resp_inter
|
|
except Exception as e:
|
|
self.conn.close()
|
|
raise ApiClientNetworkException(str(e))
|
|
|
|
|
|
class RequestInternal(object):
|
|
def __init__(self, host="", method="", uri="", header=None, data=""):
|
|
if header is None:
|
|
header = {}
|
|
self.host = host
|
|
self.method = method
|
|
self.uri = uri
|
|
self.header = header
|
|
self.data = data
|
|
|
|
def __str__(self):
|
|
headers = "\n".join("%s: %s" % (k, v) for k, v in self.header.items())
|
|
return ("Host: %s\nMethod: %s\nUri: %s\nHeader: %s\nData: %s\n"
|
|
% (self.host, self.method, self.uri, headers, self.data))
|
|
|
|
|
|
class ResponseInternal(object):
|
|
def __init__(self, status=0, header=None, data=""):
|
|
if header is None:
|
|
header = {}
|
|
self.status = status
|
|
self.header = header
|
|
self.data = data
|
|
|
|
def __str__(self):
|
|
headers = "\n".join("%s: %s" % (k, v) for k, v in self.header.items())
|
|
return ("Status: %s\nHeader: %s\nData: %s\n"
|
|
% (self.status, headers, self.data))
|