Skip to content

Commit

Permalink
Fix #63 handle retries better, add sample script
Browse files Browse the repository at this point in the history
  • Loading branch information
tjarrettveracode committed Mar 29, 2023
1 parent 9603f08 commit cb8847b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 18 deletions.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = 'veracode_api_py'
version = '0.9.38'
version = '0.9.39'
authors = [ {name = "Tim Jarrett", email="tjarrett@veracode.com"} ]
description = 'Python helper library for working with the Veracode APIs. Handles retries, pagination, and other features of the modern Veracode REST APIs.'
readme = 'README.md'
Expand All @@ -22,4 +22,4 @@ dependencies = {file = ["requirements.txt"]}
[project.urls]
"Homepage" = "https://github.com/veracode/veracode-api-py"
"Bug Tracker" = "https://github.com/veracode/veracode-api-py/issues"
"Download" = "https://github.com/veracode/veracode-api-py/archive/v_0938.tar.gz"
"Download" = "https://github.com/veracode/veracode-api-py/archive/v_0939.tar.gz"
6 changes: 6 additions & 0 deletions samples/getself.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# a simple sample to get attributes from the user's login information
from veracode_api_py import Users

me = Users().get_self()

print("You are {}".format(me['user_name']))
44 changes: 28 additions & 16 deletions veracode_api_py/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import json
import time
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

from veracode_api_signing.exceptions import VeracodeAPISigningException
from veracode_api_signing.plugin_requests import RequestsAuthPluginVeracodeHMAC
Expand All @@ -27,7 +26,6 @@ class APIHelper():

def __init__(self, debug=False):
self.baseurl = self._get_baseurl()
requests.Session().mount(self.baseurl, HTTPAdapter(max_retries=3))
self.base_rest_url = self._get_baseresturl()
self.retry_seconds = 120
self.connect_error_msg = "Connection Error"
Expand All @@ -52,26 +50,39 @@ def _get_region_url(self, type):
elif type == 'rest':
return Constants().REGIONS[self.region]['base_rest_url']

def _check_for_errors(self,theresponse, *args, **kwargs):
if theresponse.status_code in (429, 502, 503, 504):
# retry by populating new prepared request from the request in the response object
# and recalculating auth
logger.debug("Retrying request, error code {} received".format(theresponse.status_code))
session = requests.Session()
oldreq = theresponse.request
oldheaders = oldreq.headers
del oldheaders['authorization']
newreq = requests.Request(oldreq.method,oldreq.url,auth=RequestsAuthPluginVeracodeHMAC(),
headers=oldheaders)
return session.send(newreq.prepare())

def _prepare_headers(self,method,apifamily):
headers = {"User-Agent": "api.py"}
if method in ["POST", "PUT"] and apifamily=='json':
headers.update({'Content-type': 'application/json'})
return headers

def _rest_request(self, url, method, params=None, body=None, fullresponse=False, use_base_url=True):
# base request method for a REST request
myheaders = {"User-Agent": "api.py"}
if method in ["POST", "PUT"]:
myheaders.update({'Content-type': 'application/json'})

retry_strategy = Retry(total=3,
status_forcelist=[429, 500, 502, 503, 504],
method_whitelist=["HEAD", "GET", "OPTIONS"]
)
myheaders = self._prepare_headers(method,'json')

session = requests.Session()
session.mount(self.base_rest_url, HTTPAdapter(max_retries=retry_strategy))

if use_base_url:
url = self.base_rest_url + url

try:
if method == "GET":
request = requests.Request(method, url, params=params, auth=RequestsAuthPluginVeracodeHMAC(),
headers=myheaders)
headers=myheaders,
hooks={'response': self._check_for_errors})
prepared_request = request.prepare()
r = session.send(prepared_request)
elif method == "POST":
Expand All @@ -85,14 +96,15 @@ def _rest_request(self, url, method, params=None, body=None, fullresponse=False,
else:
raise VeracodeAPIError("Unsupported HTTP method")
except requests.exceptions.RequestException as e:
logger.exception(self.connect_error_msg)
logger.exception("Error: {}".format(self.connect_error_msg))
raise VeracodeAPIError(e)

if not (r.status_code == requests.codes.ok):
if r.status_code != requests.codes.ok:
logger.debug("API call returned non-200 HTTP status code: {}".format(r.status_code))

if not (r.ok):
logger.debug("Error retrieving data. HTTP status code: {}".format(r.status_code))
conv_id = r.headers['x-conversation-id']
logger.debug("Error retrieving data. HTTP status code: {}, conversation id {}".format(r.status_code,conv_id))
if r.status_code == 401:
logger.exception(
"Error [{}]: {} for request {}. Check that your Veracode API account credentials are correct.".format(
Expand Down Expand Up @@ -135,7 +147,7 @@ def _xml_request(self, url, method, params=None, files=None):
session = requests.Session()
session.mount(self.baseurl, HTTPAdapter(max_retries=3))
request = requests.Request(method, url, params=params, files=files,
auth=RequestsAuthPluginVeracodeHMAC(), headers={"User-Agent": "api.py"})
auth=RequestsAuthPluginVeracodeHMAC(), headers=self._prepare_headers(method,'xml'))
prepared_request = request.prepare()
r = session.send(prepared_request)
if 200 <= r.status_code <= 299:
Expand Down

0 comments on commit cb8847b

Please sign in to comment.