def to_dict(self, encoding='base64'): """ Return a dictionary version of the report :param encoding: required encoding for the string values (default: 'base64') :rtype: dictionary :return: dictionary representation of the report """ res = {} for k, v in self._data_fields.items(): if isinstance(v, (bytes, bytearray, six.string_types)): v = try_b64encode(v) res[k] = v for k, v in self._sub_reports.items(): res[k] = v.to_dict(encoding) return res
def transmit(self, **kwargs): """ Prepares fuzz HTTP request, sends and processes the response :param kwargs: url, method, params, querystring, etc :return: """ self.logger.debug('Transmit: {}'.format(kwargs)) try: _req_url = list() for url_part in self.base_url, kwargs['url']: if isinstance(url_part, Bits): url_part = url_part.tobytes() if isinstance(url_part, bytes): url_part = url_part.decode() _req_url.append(url_part.strip('/')) kwargs.pop('url') # Replace back the placeholder for '/' # (this happens in expand_path_variables, # but if we don't have any path_variables, it won't) request_url = '/'.join(_req_url).replace('+', '/') query_params = None if kwargs.get('params') is not None: self.logger.debug( ('Adding query params: {}'.format(kwargs.get('params', {})))) query_params = self.format_pycurl_query_param( request_url, kwargs.get('params', {})) kwargs.pop('params') if kwargs.get('path_variables') is not None: request_url = self.expand_path_variables( request_url, kwargs.get('path_variables')) kwargs.pop('path_variables') if kwargs.get('data') is not None: kwargs['data'] = self.fix_data(kwargs.get('data')) if query_params is not None: request_url = '{}{}'.format(request_url, query_params) method = kwargs['method'] self.logger.info('Request URL : {} {}'.format(method, request_url)) if kwargs.get('data') is not None: self.logger.info('Request data:{}'.format( json.dumps(dict(kwargs.get('data'))))) if isinstance(method, Bits): method = method.tobytes() if isinstance(method, bytes): method = method.decode() kwargs.pop('method') kwargs['headers'] = self.compile_headers(kwargs.get('headers')) self.logger.debug( 'Request url:{}\nRequest method: {}\nRequest headers: {}\nRequest body: {}' .format(request_url, method, json.dumps(dict(kwargs.get('headers', {})), indent=2), kwargs.get('data'))) self.report.set_status(Report.PASSED) self.report.add('request_url', request_url) self.report.add('request_method', method) self.report.add('request_headers', json.dumps(dict(kwargs.get('headers', {})))) try: resp_buff_hdrs = BytesIO() resp_buff_body = BytesIO() buffer = BytesIO() _curl = init_pycurl() _curl.setopt(pycurl.URL, self.format_pycurl_url(request_url)) _curl.setopt(pycurl.HEADERFUNCTION, self.header_function) _curl.setopt( pycurl.HTTPHEADER, self.format_pycurl_header(kwargs.get('headers', {}))) _curl.setopt(pycurl.POST, len(kwargs.get('data', {}).items())) _curl.setopt(pycurl.CUSTOMREQUEST, method) _curl.setopt(pycurl.POSTFIELDS, urllib.parse.urlencode(kwargs.get('data', {}))) _curl.setopt(pycurl.HEADERFUNCTION, resp_buff_hdrs.write) _curl.setopt(pycurl.WRITEFUNCTION, resp_buff_body.write) for retries in reversed(range(0, 3)): try: _curl.perform() except Exception as e: if retries: self.logger.error( 'Retrying... ({}) because {}'.format( retries, e)) else: raise e _return = Return() _return.status_code = _curl.getinfo(pycurl.RESPONSE_CODE) _return.headers = self.resp_headers _return.content = buffer.getvalue() _return.request = Return() _return.request.headers = kwargs.get('headers', {}) _return.request.body = kwargs.get('data', {}) _curl.close() except Exception as e: self.logger.exception(e) self.report.set_status(Report.FAILED) self.logger.error('Request failed, reason: {}'.format(e)) # self.report.add('request_sending_failed', e.msg if hasattr(e, 'msg') else e) self.report.add('request_method', method) return # overwrite request headers in report, add auto generated ones self.report.add( 'request_headers', try_b64encode(json.dumps(dict(_return.request.headers)))) self.logger.debug( 'Response code:{}\nResponse headers: {}\nResponse body: {}'. format(_return.status_code, json.dumps(dict(_return.headers), indent=2), _return.content)) self.report.add('request_body', _return.request.body) self.report.add('response', _return.content.decode()) status_code = _return.status_code if not status_code: self.report_add_basic_msg('Failed to parse http response code') elif status_code not in self.accepted_status_codes: self.report.add('parsed_status_code', status_code) self.report_add_basic_msg( ('Return code %s is not in the expected list:', status_code)) return _return except (UnicodeDecodeError, UnicodeEncodeError ) as e: # request failure such as InvalidHeader self.report_add_basic_msg( ('Failed to parse http response code, exception occurred: %s', e))
def transmit(self, **kwargs): self.logger.debug('Transmit: {}'.format(kwargs)) try: _req_url = list() for url_part in self.base_url, kwargs['url']: if isinstance(url_part, Bits): url_part = url_part.tobytes() if isinstance(url_part, bytes): url_part = url_part.decode() _req_url.append(url_part.strip('/')) kwargs.pop('url') request_url = '/'.join(_req_url) for param in ['path_variables', 'params']: if kwargs.get(param) is not None: request_url = self.expand_path_variables( request_url, kwargs.get(param)) kwargs.pop(param) self.logger.info('Request URL : {}'.format(request_url)) method = kwargs['method'] if isinstance(method, Bits): method = method.tobytes() if isinstance(method, bytes): method = method.decode() kwargs.pop('method') kwargs['headers'] = self.compile_headers(kwargs.get('headers')) self.logger.debug( 'Request url:{}\nRequest method: {}\nRequest headers: {}\nRequest body: {}' .format(request_url, method, json.dumps(dict(kwargs.get('headers', {})), indent=2), kwargs.get('params'))) self.report.set_status(Report.PASSED) self.report.add('request_url', request_url) self.report.add('request_method', method) self.report.add('request_headers', json.dumps(dict(kwargs.get('headers', {})))) try: _return = requests.request(method=method, url=request_url, verify=False, timeout=10, **kwargs) except Exception as e: self.report.set_status(Report.FAILED) self.logger.error('Request failed, reason: {}'.format(e)) self.report.add('request_sending_failed', e.reason if hasattr(e, 'reason') else e) self.report.add('request_method', method) return # overwrite request headers in report, add auto generated ones self.report.add( 'request_headers', try_b64encode(json.dumps(dict(_return.request.headers)))) self.logger.debug( 'Response code:{}\nResponse headers: {}\nResponse body: {}'. format(_return.status_code, json.dumps(dict(_return.headers), indent=2), _return.content)) self.report.add('request_body', _return.request.body) self.report.add('response', _return.content.decode()) status_code = _return.status_code if not status_code: self.report_add_basic_msg('Failed to parse http response code') elif status_code not in self.accepted_status_codes: self.report.add('parsed_status_code', status_code) self.report_add_basic_msg( ('Return code %s is not in the expected list:', status_code)) return _return except (RequestException, UnicodeDecodeError, UnicodeEncodeError ) as e: # request failure such as InvalidHeader self.report_add_basic_msg( ('Failed to parse http response code, exception occurred: %s', e))