Exemple #1
0
def call_salesforce(url, method, session, headers, **kwargs):
    """Utility that generates a request to salesforce using urllib3 instead of
    requests package. This is necessary for connections that use the mutual
    authentication with encrypted certificates, the package requests  can't
    handle it.

    PrepareRequest and HttpAdapter are used so that it returns a regular
    Response <requests.Response> that is expected for the rest of the process.
    """
    additional_headers = kwargs.pop('additional_headers', dict())
    headers.update(additional_headers or dict())

    request_args = {'method': method.upper(), 'headers': headers}

    context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
    # We will try and load the cert file and pass from the environment variables
    cert_file = os.environ.get('SIMPLE_SALESFORCE_CERT_FILE', None)
    cert_pass = os.environ.get('SIMPLE_SALESFORCE_PASSWORD', None)
    if cert_file and cert_pass:
        context.load_cert_chain(certfile=cert_file, password=cert_pass)

    request = PreparedRequest()
    parsed = urlparse(url)
    parsed = parsed._replace(netloc="{}:{}".format(parsed.hostname, 8443))
    request.prepare(url=parsed.geturl(),
                    data=kwargs.get('data') or {},
                    **request_args)

    http = PoolManager(ssl_context=context, cert_reqs='CERT_REQUIRED')
    result = http.urlopen(url=request.url,
                          body=request.body,
                          redirect=False,
                          assert_same_host=False,
                          preload_content=False,
                          decode_content=False,
                          **request_args)

    adapter = HTTPAdapter()
    response = adapter.build_response(request, result)

    if response.status_code >= 300:
        from simple_salesforce.util import exception_handler
        exception_handler(response)

    adapter.close()
    return response
Exemple #2
0
    def download_text(self, *, destination: Optional[str] = None) -> str:
        """
        Download the body of the set url.

        .. note::
            if :code:`destination` is set to :code:`None`,
            we only return the output.

            Otherwise, we save the output into the given
            destination, but we also return the output.

        :param destination: The download destination.

        :raise UnableToDownload: When could not unable to download the URL.
        """

        session = requests.Session()

        retries = Retry(total=self.retries, backoff_factor=3)
        adapter = HTTPAdapter(max_retries=retries)

        session.mount("http://", adapter)
        session.mount("https://", adapter)

        req = session.get(self.url, verify=self.certificate_validation)

        if req.status_code == 200:
            response = req.text

            if destination and isinstance(destination, str):
                FileHelper(destination).write(req.text, overwrite=True)

            adapter.close()
            req.close()
            return response

        adapter.close()
        session.close()
        raise PyFunceble.helpers.exceptions.UnableToDownload(
            f"{req.url} (retries: {self.retries} | status code: {req.status_code})"
        )
Exemple #3
0
class BetamaxAdapter(BaseAdapter):
    """This object is an implementation detail of the library.

    It is not meant to be a public API and is not exported as such.

    """

    def __init__(self, **kwargs):
        super(BetamaxAdapter, self).__init__()
        self.cassette = None
        self.cassette_name = None
        self.old_adapters = kwargs.pop('old_adapters', {})
        self.http_adapter = HTTPAdapter(**kwargs)
        self.serialize = None
        self.options = {}

    def cassette_exists(self):
        """Check if cassette exists on file system.

        :returns: bool -- True if exists, False otherwise
        """
        if self.cassette_name and os.path.exists(self.cassette_name):
            return True
        return False

    def close(self):
        """Propagate close to underlying adapter."""
        self.http_adapter.close()

    def eject_cassette(self):
        """Eject currently loaded cassette."""
        if self.cassette:
            self.cassette.eject()
        self.cassette = None  # Allow self.cassette to be garbage-collected

    def load_cassette(self, cassette_name, serialize, options):
        """Load cassette.

        Loads a previously serialized http response as a cassette

        :param str cassette_name: (required), name of cassette
        :param str serialize: (required), type of serialization i.e 'json'
        :options dict options: (required), options for cassette
        """
        self.cassette_name = cassette_name
        self.serialize = serialize
        self.options.update(options.items())
        placeholders = self.options.get('placeholders', {})
        cassette_options = {}

        default_options = cassette.Cassette.default_cassette_options

        match_requests_on = self.options.get(
            'match_requests_on', default_options['match_requests_on']
            )

        cassette_options['preserve_exact_body_bytes'] = self.options.get(
            'preserve_exact_body_bytes',
            )

        cassette_options['allow_playback_repeats'] = self.options.get(
            'allow_playback_repeats'
            )

        cassette_options['record_mode'] = self.options.get('record')

        for option, value in list(cassette_options.items()):
            if value is None:
                cassette_options.pop(option)

        self.cassette = cassette.Cassette(
            cassette_name, serialize, placeholders=placeholders,
            cassette_library_dir=self.options.get('cassette_library_dir'),
            **cassette_options
            )

        if 'record' in self.options:
            self.cassette.record_mode = self.options['record']

        # NOTE(sigmavirus24): Cassette.match_options is a set, might as well
        # use that instead of overriding it.
        self.cassette.match_options.update(match_requests_on)

        re_record_interval = timedelta.max
        if self.options.get('re_record_interval'):
            re_record_interval = timedelta(self.options['re_record_interval'])

        now = datetime.utcnow()
        if re_record_interval < (now - self.cassette.earliest_recorded_date):
            self.cassette.clear()

    def send(self, request, stream=False, timeout=None, verify=True,
             cert=None, proxies=None):
        """Send request.

        :param request request: request
        :returns: A Response object
        """
        interaction = None
        current_cassette = self.cassette

        if not current_cassette:
            raise BetamaxError('No cassette was specified or found.')

        if current_cassette.interactions:
            interaction = current_cassette.find_match(request)

        if not interaction and current_cassette.is_recording():
            interaction = self.send_and_record(
                request, stream, timeout, verify, cert, proxies
                )

        if not interaction:
            raise BetamaxError(unhandled_request_message(request,
                                                         current_cassette))

        resp = interaction.as_response()
        resp.connection = self
        return resp

    def send_and_record(self, request, stream=False, timeout=None,
                        verify=True, cert=None, proxies=None):
        """Send request and record response.

        The response will be serialized and saved to a
        cassette which can be replayed in the future.

        :param request request: request
        :param bool stream: (optional) defer download until content is accessed
        :param float timeout: (optional) time to wait for a response
        :param bool verify: (optional) verify SSL certificate
        :param str cert: (optional) path to SSL client
        :param proxies dict: (optional) mapping protocol to URL of the proxy
        :return: Interaction
        :rtype: class:`betamax.cassette.Interaction`
        """
        adapter = self.find_adapter(request.url)
        response = adapter.send(
            request, stream=True, timeout=timeout, verify=verify,
            cert=cert, proxies=proxies
            )
        return self.cassette.save_interaction(response, request)

    def find_adapter(self, url):
        """Find adapter.

        Searches for an existing adapter where the url and prefix match.

        :param url str: (required) url of the adapter
        :returns: betamax adapter
        """
        for (prefix, adapter) in self.old_adapters.items():

            if url.lower().startswith(prefix):
                return adapter
Exemple #4
0
class BetamaxAdapter(BaseAdapter):

    """This object is an implementation detail of the library.

    It is not meant to be a public API and is not exported as such.

    """

    def __init__(self, **kwargs):
        super(BetamaxAdapter, self).__init__()
        self.cassette = None
        self.cassette_name = None
        self.old_adapters = kwargs.pop('old_adapters', {})
        self.http_adapter = HTTPAdapter(**kwargs)
        self.serialize = None
        self.options = {}

    def cassette_exists(self):
        if self.cassette_name and os.path.exists(self.cassette_name):
            return True
        return False

    def close(self):
        self.http_adapter.close()

    def eject_cassette(self):
        if self.cassette:
            self.cassette.eject()
        self.cassette = None  # Allow self.cassette to be garbage-collected

    def load_cassette(self, cassette_name, serialize, options):
        self.cassette_name = cassette_name
        self.serialize = serialize
        self.options.update(options.items())
        placeholders = self.options.get('placeholders', [])

        default_options = Cassette.default_cassette_options

        match_requests_on = self.options.get(
            'match_requests_on', default_options['match_requests_on']
            )

        preserve_exact_body_bytes = self.options.get(
            'preserve_exact_body_bytes',
            )

        self.cassette = Cassette(
            cassette_name, serialize, placeholders=placeholders,
            record_mode=self.options.get('record'),
            preserve_exact_body_bytes=preserve_exact_body_bytes
            )

        if 'record' in self.options:
            self.cassette.record_mode = self.options['record']
        self.cassette.match_options = match_requests_on

        re_record_interval = timedelta.max
        if self.options.get('re_record_interval'):
            re_record_interval = timedelta(self.options['re_record_interval'])

        now = datetime.utcnow()
        if re_record_interval < (now - self.cassette.earliest_recorded_date):
            self.cassette.clear()

    def send(self, request, stream=False, timeout=None, verify=True,
             cert=None, proxies=None):
        interaction = None

        if not self.cassette:
            raise BetamaxError('No cassette was specified or found.')

        if self.cassette.interactions:
            interaction = self.cassette.find_match(request)

        if not interaction and self.cassette.is_recording():
            interaction = self.send_and_record(
                request, stream, timeout, verify, cert, proxies
                )

        if not interaction:
            raise BetamaxError(unhandled_request_message(request,
                                                         self.cassette))

        resp = interaction.as_response()
        resp.connection = self
        return resp

    def send_and_record(self, request, stream=False, timeout=None,
                        verify=True, cert=None, proxies=None):
        adapter = self.find_adapter(request.url)
        response = adapter.send(
            request, stream=True, timeout=timeout, verify=verify,
            cert=cert, proxies=proxies
            )
        self.cassette.save_interaction(response, request)
        return self.cassette.interactions[-1]

    def find_adapter(self, url):
        for (prefix, adapter) in self.old_adapters.items():

            if url.lower().startswith(prefix):
                return adapter
Exemple #5
0
class BetamaxAdapter(BaseAdapter):
    """This object is an implementation detail of the library.

    It is not meant to be a public API and is not exported as such.

    """
    def __init__(self, **kwargs):
        super(BetamaxAdapter, self).__init__()
        self.cassette = None
        self.cassette_name = None
        self.old_adapters = kwargs.pop('old_adapters', {})
        self.http_adapter = HTTPAdapter(**kwargs)
        self.serialize = None
        self.options = {}

    def cassette_exists(self):
        if self.cassette_name and os.path.exists(self.cassette_name):
            return True
        return False

    def close(self):
        self.http_adapter.close()

    def eject_cassette(self):
        if self.cassette:
            self.cassette.eject()
        self.cassette = None  # Allow self.cassette to be garbage-collected

    def load_cassette(self, cassette_name, serialize, options):
        self.cassette_name = cassette_name
        self.serialize = serialize
        self.options.update(options.items())
        placeholders = self.options.get('placeholders', [])

        default_options = Cassette.default_cassette_options

        match_requests_on = self.options.get(
            'match_requests_on', default_options['match_requests_on'])

        preserve_exact_body_bytes = self.options.get(
            'preserve_exact_body_bytes', )

        self.cassette = Cassette(
            cassette_name,
            serialize,
            placeholders=placeholders,
            record_mode=self.options.get('record'),
            preserve_exact_body_bytes=preserve_exact_body_bytes,
            cassette_library_dir=self.options.get('cassette_library_dir'))

        if 'record' in self.options:
            self.cassette.record_mode = self.options['record']
        self.cassette.match_options = match_requests_on

        re_record_interval = timedelta.max
        if self.options.get('re_record_interval'):
            re_record_interval = timedelta(self.options['re_record_interval'])

        now = datetime.utcnow()
        if re_record_interval < (now - self.cassette.earliest_recorded_date):
            self.cassette.clear()

    def send(self,
             request,
             stream=False,
             timeout=None,
             verify=True,
             cert=None,
             proxies=None):
        interaction = None

        if not self.cassette:
            raise BetamaxError('No cassette was specified or found.')

        if self.cassette.interactions:
            interaction = self.cassette.find_match(request)

        if not interaction and self.cassette.is_recording():
            interaction = self.send_and_record(request, stream, timeout,
                                               verify, cert, proxies)

        if not interaction:
            raise BetamaxError(
                unhandled_request_message(request, self.cassette))

        resp = interaction.as_response()
        resp.connection = self
        return resp

    def send_and_record(self,
                        request,
                        stream=False,
                        timeout=None,
                        verify=True,
                        cert=None,
                        proxies=None):
        adapter = self.find_adapter(request.url)
        response = adapter.send(request,
                                stream=True,
                                timeout=timeout,
                                verify=verify,
                                cert=cert,
                                proxies=proxies)
        self.cassette.save_interaction(response, request)
        return self.cassette.interactions[-1]

    def find_adapter(self, url):
        for (prefix, adapter) in self.old_adapters.items():

            if url.lower().startswith(prefix):
                return adapter
Exemple #6
0
class BetamaxAdapter(BaseAdapter):

    """This object is an implementation detail of the library.

    It is not meant to be a public API and is not exported as such.

    """

    def __init__(self, **kwargs):
        super(BetamaxAdapter, self).__init__()
        self.cassette = None
        self.cassette_name = None
        self.http_adapter = HTTPAdapter(**kwargs)
        self.serialize = None
        self.options = {}

    def cassette_exists(self):
        if self.cassette_name and os.path.exists(self.cassette_name):
            return True
        return False

    def close(self):
        self.http_adapter.close()

    def eject_cassette(self):
        if self.cassette:
            self.cassette.eject()
        self.cassette = None  # Allow self.cassette to be garbage-collected

    def load_cassette(self, cassette_name, serialize, options):
        self.cassette_name = cassette_name
        self.serialize = serialize
        self.options.update(options)
        placeholders = self.options.get('placeholders')

        # load cassette into memory
        if self.cassette_exists():
            self.cassette = Cassette(cassette_name, serialize,
                                     placeholders=placeholders)
        elif os.path.exists(os.path.dirname(cassette_name)):
            self.cassette = Cassette(cassette_name, serialize, 'w+',
                                     placeholders=placeholders)
        else:
            raise RuntimeError(
                'No cassette could be loaded or %s does not exist.' %
                os.path.dirname(cassette_name)
            )

        self.cassette.record_mode = self.options['record']

        re_record_interval = timedelta.max
        if self.options.get('re_record_interval'):
            re_record_interval = timedelta(self.options['re_record_interval'])

        now = datetime.utcnow()
        if re_record_interval < (now - self.cassette.earliest_recorded_date):
            self.cassette.clear()

    def send(self, request, stream=False, timeout=None, verify=True,
             cert=None, proxies=None):
        interaction = None
        match_on = Cassette.default_cassette_options['match_requests_on']
        response = None

        if not self.cassette:
            raise BetamaxError('No cassette was specified or found.')

        if self.cassette.interactions:
            self.cassette.match_options = set(match_on)
            interaction = self.cassette.find_match(request)

        if not interaction and self.cassette.is_recording():
            response = self.http_adapter.send(
                request, stream=True, timeout=timeout, verify=verify,
                cert=cert, proxies=proxies
                )
            self.cassette.save_interaction(response, request)
            interaction = self.cassette.interactions[-1]

        if not interaction:
            raise BetamaxError('A request was made that could not be handled')

        return interaction.as_response()