def _perform_custom_request(self, ctxt, method, url, header_count, header_keys, header_values, response): # Cast response to an array of length 1 so ctypes can write to the pointer # out_response = ((BNDownloadInstanceResponse*)[1])response out_response = (ctypes.POINTER(core.BNDownloadInstanceResponse) * 1).from_address(ctypes.addressof(response.contents)) try: # Extract headers keys_ptr = ctypes.cast(header_keys, ctypes.POINTER(ctypes.c_char_p)) values_ptr = ctypes.cast(header_values, ctypes.POINTER(ctypes.c_char_p)) header_key_array = (ctypes.c_char_p * header_count).from_address( ctypes.addressof(keys_ptr.contents)) header_value_array = (ctypes.c_char_p * header_count).from_address( ctypes.addressof(values_ptr.contents)) headers = {} for i in range(header_count): headers[header_key_array[i]] = header_value_array[i] # Read all data data = b'' while True: read_buffer = ctypes.create_string_buffer(0x1000) read_len = core.BNReadDataForDownloadInstance( self.handle, ctypes.cast(read_buffer, ctypes.POINTER(ctypes.c_uint8)), 0x1000) if read_len == 0: break data += read_buffer[:read_len] py_response = self.perform_custom_request(method, url, headers, data) if py_response is not None: # Assign to an instance variable so the memory stays live until the request is done self.bn_response = core.BNDownloadInstanceResponse() self.bn_response.statusCode = py_response.status_code self.bn_response.headerCount = len(py_response.headers) self.bn_response.headerKeys = (ctypes.c_char_p * len(py_response.headers))() self.bn_response.headerValues = (ctypes.c_char_p * len(py_response.headers))() for i, (key, value) in enumerate(py_response.headers.items()): self.bn_response.headerKeys[i] = core.BNAllocString( pyNativeStr(key)) self.bn_response.headerValues[i] = core.BNAllocString( pyNativeStr(value)) out_response[0] = ctypes.pointer(self.bn_response) else: out_response[0] = None return 0 if py_response is not None else -1 except: out_response[0] = None log.log_error(traceback.format_exc()) return -1
def _get_current_view(self, ctxt): try: view = self.get_current_view() except: log.log_error(traceback.format_exc()) view = "" return core.BNAllocString(view)
def _get_data(self, ctxt, key: str): try: data = self.perform_get_data(key) return core.BNAllocString(data) except: log_error(traceback.format_exc()) return None
def _get_directory_name_input(self, ctxt, result, prompt, default_name): try: value = self.get_directory_name_input(prompt, default_name) if value is None: return False result[0] = core.BNAllocString(str(value)) return True except: log.log_error(traceback.format_exc())
def _perform_custom_request(self, ctxt, method, url, header_count, header_keys, header_values, response): # Cast response to an array of length 1 so ctypes can write to the pointer # out_response = ((BNDownloadInstanceResponse*)[1])response out_response = (ctypes.POINTER(core.BNDownloadInstanceResponse) * 1).from_address(ctypes.addressof( response.contents)) # type: ignore try: # Extract headers keys_ptr = ctypes.cast(header_keys, ctypes.POINTER(ctypes.c_char_p)) values_ptr = ctypes.cast(header_values, ctypes.POINTER(ctypes.c_char_p)) header_key_array = (ctypes.c_char_p * header_count).from_address( ctypes.addressof(keys_ptr.contents)) header_value_array = (ctypes.c_char_p * header_count).from_address( ctypes.addressof(values_ptr.contents)) headers = {} for i in range(header_count): headers[header_key_array[i]] = header_value_array[i] # Generator function that returns a chunk of data on every iteration def data_generator(): while True: read_buffer = ctypes.create_string_buffer(0x1000) read_len = core.BNReadDataForDownloadInstance( self.handle, ctypes.cast(read_buffer, ctypes.POINTER(ctypes.c_uint8)), 0x1000) if read_len == 0: break if read_len < 0: raise IOError() yield read_buffer[:read_len] try: py_response = self.perform_custom_request( method, url, headers, data_generator()) except Exception as e: out_response[0] = None core.BNSetErrorForDownloadInstance(self.handle, e.__class__.__name__) log_error(traceback.format_exc()) return -1 if py_response is not None: # Assign to an instance variable so the memory stays live until the request is done self.bn_response = core.BNDownloadInstanceResponse() self.bn_response.statusCode = py_response.status_code self.bn_response.headerCount = len(py_response.headers) self.bn_response.headerKeys = (ctypes.c_char_p * len(py_response.headers))() self.bn_response.headerValues = (ctypes.c_char_p * len(py_response.headers))() for i, (key, value) in enumerate(py_response.headers.items()): self.bn_response.headerKeys[i] = core.BNAllocString( key.decode('utf8')) self.bn_response.headerValues[i] = core.BNAllocString( value.decode('utf8')) out_response[0] = ctypes.pointer(self.bn_response) else: out_response[0] = None return 0 if py_response is not None else -1 except: out_response[0] = None log_error(traceback.format_exc()) return -1
def _fill_core_result(self, value): value.stringResult = core.BNAllocString(str(self._result))