#!/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))
Memory