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
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})" )
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
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
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
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()