예제 #1
0
    def request(self, method, url, headers, post_data=None):
        if six.PY3 and isinstance(post_data, six.string_types):
            post_data = post_data.encode('utf-8')

        req = urllib.request.Request(url, post_data, headers)

        if method not in ('get', 'post'):
            req.get_method = lambda: method.upper()

        try:
            # use the custom proxy tied opener, if any.
            # otherwise, fall to the default urllib opener.
            response = self._opener.open(req) \
                if self._opener \
                else urllib.request.urlopen(req)
            rbody = response.read()
            rcode = response.code
            headers = dict(response.info())
        except urllib.error.HTTPError as e:
            rcode = e.code
            rbody = e.read()
            headers = dict(e.info())
        except (urllib.error.URLError, ValueError) as e:
            self._handle_request_error(e)
        lh = dict((k.lower(), v) for k, v in six.iteritems(dict(headers)))
        return rbody, rcode, lh
예제 #2
0
    def refresh_from(self,
                     values,
                     api_key=None,
                     partial=False,
                     last_response=None):
        self.api_key = api_key or getattr(values, 'api_key', None)
        self._last_response = last_response

        # Wipe old state before setting new.  This is useful for e.g.
        # updating a customer, where there is no persistent card
        # parameter.  Mark those values which don't persist as transient
        if partial:
            self._unsaved_values = (self._unsaved_values - set(values))
        else:
            removed = set(self.keys()) - set(values)
            self._transient_values = self._transient_values | removed
            self._unsaved_values = set()
            self.clear()

        self._transient_values = self._transient_values - set(values)

        for k, v in six.iteritems(values):
            super(PingppObject,
                  self).__setitem__(k,
                                    util.convert_to_pingpp_object(v, api_key))

        self._previous = values
예제 #3
0
    def __deepcopy__(self, memo):
        copied = self.__copy__()
        memo[id(self)] = copied

        for k, v in six.iteritems(self):
            super(PingppObject, copied).__setitem__(k, deepcopy(v, memo))

        return copied
예제 #4
0
    def __copy__(self):
        copied = PingppObject(self.get('id'), self.api_key)

        copied._retrieve_params = self._retrieve_params

        for k, v in six.iteritems(self):
            super(PingppObject, copied).__setitem__(k, v)

        return copied
예제 #5
0
    def request_raw(self, method, url, params=None, supplied_headers=None):
        """
        Mechanism for issuing an API call
        """

        if self.api_key:
            my_api_key = self.api_key
        else:
            from pingpp import api_key
            my_api_key = api_key

        if my_api_key is None:
            raise error.AuthenticationError(
                'No API key provided. (HINT: set your API key using '
                '"pingpp.api_key = <API-KEY>"). You can generate API keys '
                'from the Ping++ web interface.  '
                'See https://www.pingxx.com/api for details.')

        abs_url = '%s%s' % (self.api_base, url)
        request_uri = url

        if method == 'get' or method == 'delete':
            if params:
                encoded_params = urlencode(list(_api_encode(params or {})))
                abs_url = _build_api_url(abs_url, encoded_params)
                request_uri = _build_api_url(url, encoded_params)
            post_data = None
        elif method == 'post' or method == 'put':
            post_data = util.json.dumps(params).encode("utf-8")
        else:
            raise error.APIConnectionError(
                'Unrecognized HTTP method %r.  This may indicate a bug in the '
                'Ping++ bindings. ' % (method, ))

        headers = self.request_headers(my_api_key, method)

        if supplied_headers is not None:
            for key, value in six.iteritems(supplied_headers):
                headers[key] = value

        request_utc_timestamp = _get_utc_timestamp()
        headers['Pingplusplus-Request-Timestamp'] = request_utc_timestamp
        rsa_data = self.get_rsa_verify_data(post_data, request_uri,
                                            int(request_utc_timestamp))
        util.log_debug('Signing data', data=rsa_data)

        privkey = self.get_private_key()
        if privkey is not None:
            headers['Pingplusplus-Signature'] = self.rsa_sign(
                privkey, rsa_data)

        rbody, rcode, rheaders = self.execute_request_with_retry(
            method, abs_url, headers, post_data)

        return rbody, rcode, rheaders, my_api_key
예제 #6
0
    def request(self, method, url, headers, post_data=None):
        b = util.io.BytesIO()
        rheaders = util.io.BytesIO()

        self._curl.reset()

        proxy = self._get_proxy(url)
        if proxy:
            if proxy.hostname:
                self._curl.setopt(pycurl.PROXY, proxy.hostname)
            if proxy.port:
                self._curl.setopt(pycurl.PROXYPORT, proxy.port)
            if proxy.username or proxy.password:
                self._curl.setopt(pycurl.PROXYUSERPWD,
                                  "%s:%s" % (proxy.username, proxy.password))

        if method == 'get':
            self._curl.setopt(pycurl.HTTPGET, 1)
        elif method == 'post':
            self._curl.setopt(pycurl.POST, 1)
            self._curl.setopt(pycurl.POSTFIELDS, post_data)
        else:
            self._curl.setopt(pycurl.CUSTOMREQUEST, method.upper())

        # pycurl doesn't like unicode URLs
        self._curl.setopt(pycurl.URL, util.utf8(url))

        self._curl.setopt(pycurl.WRITEFUNCTION, b.write)
        self._curl.setopt(pycurl.NOSIGNAL, 1)
        self._curl.setopt(pycurl.CONNECTTIMEOUT, pingpp.connect_timeout)
        self._curl.setopt(pycurl.TIMEOUT, pingpp.timeout)
        self._curl.setopt(
            pycurl.HTTPHEADER,
            ['%s: %s' % (k, v) for k, v in six.iteritems(dict(headers))])
        if self._verify_ssl_certs:
            self._curl.setopt(pycurl.CAINFO,
                              util.ca_bundle_path(self._ca_bundle))
        else:
            self._curl.setopt(pycurl.SSL_VERIFYHOST, False)

        try:
            self._curl.perform()
        except pycurl.error as e:
            self._handle_request_error(e)
        rbody = b.getvalue().decode('utf-8')
        rcode = self._curl.getinfo(pycurl.RESPONSE_CODE)
        headers = self.parse_headers(rheaders.getvalue().decode('utf-8'))

        return rbody, rcode, headers
예제 #7
0
    def serialize(self, previous):
        params = {}
        unsaved_keys = self._unsaved_values or set()
        previous = previous or self._previous or {}

        for k, v in six.iteritems(self):
            if k == 'id' or (isinstance(k, str) and k.startswith('_')):
                continue
            elif isinstance(v, pingpp.api_resources.abstract.APIResource):
                continue
            elif hasattr(v, 'serialize'):
                child = v.serialize(previous.get(k, None))
                if child != {}:
                    params[k] = child
            elif k in unsaved_keys:
                params[k] = _compute_diff(v, previous.get(k, None))
            elif k == 'additional_owners' and v is not None:
                params[k] = _serialize_list(v, previous.get(k, None))

        return params
예제 #8
0
def _api_encode(data):
    for key, value in six.iteritems(data):
        key = util.utf8(key)
        if value is None:
            continue
        elif hasattr(value, 'pingpp_id'):
            yield (key, value.pingpp_id)
        elif isinstance(value, list) or isinstance(value, tuple):
            for sv in value:
                if isinstance(sv, dict):
                    subdict = _encode_nested_dict(key, sv, fmt='%s[][%s]')
                    for k, v in _api_encode(subdict):
                        yield (k, v)
                else:
                    yield ("%s[]" % (key, ), util.utf8(sv))
        elif isinstance(value, dict):
            subdict = _encode_nested_dict(key, value)
            for subkey, subvalue in _api_encode(subdict):
                yield (subkey, subvalue)
        elif isinstance(value, datetime.datetime):
            yield (key, _encode_datetime(value))
        else:
            yield (key, util.utf8(value))
예제 #9
0
 def parse_headers(self, data):
     if '\r\n' not in data:
         return {}
     raw_headers = data.split('\r\n', 1)[1]
     headers = email.message_from_string(raw_headers)
     return dict((k.lower(), v) for k, v in six.iteritems(dict(headers)))
예제 #10
0
def _encode_nested_dict(key, data, fmt='%s[%s]'):
    d = {}
    for subkey, subvalue in six.iteritems(data):
        d[fmt % (key, subkey)] = subvalue
    return d