Files
wlan-lanforge-scripts/py-json/LANforge/LFRequest.py
Matthew Stidham f9b3347138 LFRequest: Fix whitespace
Signed-off-by: Matthew Stidham <stidmatt@gmail.com>
2021-12-06 11:24:18 -08:00

421 lines
17 KiB
Python

#!/usr/bin/env python3
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Class holds default settings for json requests -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
import logging
import sys
import os
from pprint import pformat, PrettyPrinter
import urllib
from urllib import request
import json
if sys.version_info[0] != 3:
print("This script requires Python 3")
exit()
sys.path.append(os.path.join(os.path.abspath(__file__ + "../../../../")))
debug_printer = PrettyPrinter(indent=2)
class LFRequest:
Default_Base_URL = "http://localhost:8080"
No_Data = {'No Data': 0}
requested_url = ""
post_data = No_Data
default_headers = {'Accept': 'application/json'}
proxies = None
logger = logging.getLogger(__name__)
def __init__(self, url=None,
uri=None,
proxies_=None,
debug_=False,
die_on_error_=False):
self.debug = debug_
self.die_on_error = die_on_error_
self.error_list = []
# please see this discussion on ProxyHandlers:
# https://docs.python.org/3/library/urllib.request.html#urllib.request.ProxyHandler
# but this makes much more sense:
# https://gist.github.com/aleiphoenix/4159510
# if debug_:
# if proxies_ is None:
# print("LFRequest_init_: no proxies_")
# else:
# print("LFRequest: proxies_: ")
# pprint.pprint(proxies_)
if (proxies_ is not None) and (len(proxies_) > 0):
if ("http" not in proxies_) and ("https" not in proxies_):
raise ValueError("Neither http or https set in proxy definitions. Expects proxy={'http':, 'https':, }")
self.proxies = proxies_
# if debug_:
# if self.proxies is None:
# print("LFRequest_init_: no proxies")
# else:
# print("LFRequest: proxies: ")
# pprint.pprint(self.proxies)
if not url.startswith("http://") and not url.startswith("https://"):
self.logger.warning("No http:// or https:// found, prepending http:// to " + url)
url = "http://" + url
if uri is not None:
if not url.endswith('/') and not uri.startswith('/'):
url += '/'
self.requested_url = url + uri
else:
self.requested_url = url
if self.requested_url is None:
raise Exception("Bad LFRequest of url[%s] uri[%s] -> None" % (url, uri))
if self.requested_url.find('//'):
protopos = self.requested_url.find("://")
self.requested_url = self.requested_url[:protopos + 2] + self.requested_url[protopos + 2:].replace("//",
"/")
# finding '#' prolly indicates a macvlan (eth1#0)
# finding ' ' prolly indicates a field name that should imply %20
if self.requested_url.find('#') >= 1:
self.requested_url = self.requested_url.replace('#', '%23')
if self.requested_url.find(' ') >= 1:
self.requested_url = self.requested_url.replace(' ', '+')
self.logger.debug("new LFRequest[%s]" % self.requested_url)
# request first url on stack
def formPost(self, show_error=True, debug=False, die_on_error_=False):
return self.form_post(show_error=show_error, debug=debug, die_on_error_=die_on_error_)
def form_post(self, show_error=True, debug=False, die_on_error_=False):
if self.die_on_error:
die_on_error_ = True
if not debug and self.debug:
debug = True
responses = []
urlenc_data = ""
# https://stackoverflow.com/a/59635684/11014343
if (self.proxies is not None) and (len(self.proxies) > 0):
# https://stackoverflow.com/a/59635684/11014343
opener = request.build_opener(request.ProxyHandler(self.proxies))
request.install_opener(opener)
self.logger.debug("formPost: url: " + self.requested_url)
if (self.post_data is not None) and (self.post_data is not self.No_Data):
urlenc_data = urllib.parse.urlencode(self.post_data).encode("utf-8")
self.logger.debug("formPost: data looks like:" + str(urlenc_data))
self.logger.debug("formPost: url: " + self.requested_url)
myrequest = request.Request(url=self.requested_url,
data=urlenc_data,
headers=self.default_headers)
else:
myrequest = request.Request(url=self.requested_url, headers=self.default_headers)
self.logger.error("No data for this formPost?")
myrequest.headers['Content-type'] = 'application/x-www-form-urlencoded'
resp = ''
try:
resp = urllib.request.urlopen(myrequest)
responses.append(resp)
return responses[0]
except urllib.error.HTTPError as error:
print_diagnostics(url_=self.requested_url,
request_=myrequest,
responses_=responses,
error_=error,
error_list_=self.error_list,
debug_=debug)
except urllib.error.URLError as uerror:
print_diagnostics(url_=self.requested_url,
request_=myrequest,
responses_=responses,
error_=uerror,
error_list_=self.error_list,
debug_=debug)
if die_on_error_ or self.die_on_error:
exit(1)
return None
def jsonPost(self, show_error=True, debug=False, die_on_error_=False, response_json_list_=None):
return self.json_post(show_error=show_error, debug=debug, die_on_error_=die_on_error_,
response_json_list_=response_json_list_)
def json_post(self, show_error=True, debug=False, die_on_error_=False, response_json_list_=None, method_='POST'):
if not debug and self.debug:
debug = True
if self.die_on_error:
die_on_error_ = True
responses = []
if (self.proxies is not None) and (len(self.proxies) > 0):
opener = urllib.request.build_opener(request.ProxyHandler(self.proxies))
urllib.request.install_opener(opener)
if (self.post_data is not None) and (self.post_data is not self.No_Data):
myrequest = request.Request(url=self.requested_url,
method=method_,
data=json.dumps(self.post_data).encode("utf-8"),
headers=self.default_headers)
else:
myrequest = request.Request(url=self.requested_url, headers=self.default_headers)
self.logger.error("No data for this jsonPost?")
myrequest.headers['Content-type'] = 'application/json'
# https://stackoverflow.com/a/59635684/11014343
try:
resp = urllib.request.urlopen(myrequest)
resp_data = resp.read().decode('utf-8')
if debug and die_on_error_:
self.logger.debug("----- LFRequest::json_post:128 debug: --------------------------------------------")
self.logger.debug("URL: <%s> status: %d " % (self.requested_url, resp.status))
if resp.status != 200:
self.logger.debug(pformat(resp.getheaders()))
self.logger.debug("----- resp_data:128 -------------------------------------------------")
self.logger.debug(resp_data)
self.logger.debug("-------------------------------------------------")
responses.append(resp)
if response_json_list_ is not None:
if type(response_json_list_) is not list:
raise ValueError("reponse_json_list_ needs to be type list")
j = json.loads(resp_data)
if debug:
self.logger.debug(
"----- LFRequest::json_post:140 debug: --------------------------------------------")
self.logger.debug(pformat(j))
self.logger.debug("-------------------------------------------------")
response_json_list_.append(j)
return responses[0]
except urllib.error.HTTPError as error:
print_diagnostics(url_=self.requested_url,
request_=myrequest,
responses_=responses,
error_=error,
debug_=debug)
except urllib.error.URLError as uerror:
print_diagnostics(url_=self.requested_url,
request_=myrequest,
responses_=responses,
error_=uerror,
debug_=debug)
if die_on_error_:
exit(1)
return None
def json_put(self, show_error=True, debug=False, die_on_error_=False, response_json_list_=None):
return self.json_post(show_error=show_error,
debug=debug,
die_on_error_=die_on_error_,
response_json_list_=response_json_list_,
method_='PUT')
def json_delete(self, show_error=True, debug=False, die_on_error_=False, response_json_list_=None):
return self.get_as_json(method_='DELETE')
def get(self, method_='GET'):
if self.debug:
self.logger.debug("LFUtils.get: url: " + self.requested_url)
# https://stackoverflow.com/a/59635684/11014343
if (self.proxies is not None) and (len(self.proxies) > 0):
opener = request.build_opener(request.ProxyHandler(self.proxies))
# opener = urllib.request.build_opener(myrequest.ProxyHandler(self.proxies))
request.install_opener(opener)
myrequest = request.Request(url=self.requested_url,
headers=self.default_headers,
method=method_)
myresponses = []
try:
myresponses.append(request.urlopen(myrequest))
return myresponses[0]
except urllib.error.HTTPError as error:
print_diagnostics(url_=self.requested_url,
request_=myrequest,
responses_=myresponses,
error_=error,
error_list_=self.error_list,
debug_=self.debug)
except urllib.error.URLError as uerror:
print_diagnostics(url_=self.requested_url,
request_=myrequest,
responses_=myresponses,
error_=uerror,
error_list_=self.error_list,
debug_=self.debug)
if self.die_on_error:
exit(1)
return None
def getAsJson(self):
return self.get_as_json()
def get_as_json(self, method_='GET'):
responses = list()
responses.append(self.get(method_=method_))
if len(responses) < 1:
if self.debug and self.has_errors():
self.print_errors()
return None
if responses[0] is None:
self.logger.debug("No response from " + self.requested_url)
return None
json_data = json.loads(responses[0].read().decode('utf-8'))
return json_data
def addPostData(self, data):
self.add_post_data(data=data)
def add_post_data(self, data):
"""
TODO: this is a setter and should be named 'set_post_data'
:param data: dictionary of parameters for post
:return: nothing
"""
self.post_data = data
def has_errors(self):
return (True, False)[len(self.error_list) > 0]
def print_errors(self):
if not self.has_errors:
self.logger.debug("---------- no errors ----------")
return
for err in self.error_list:
self.logger.error("error: %s" % err)
def plain_get(url_=None, debug_=False, die_on_error_=False, proxies_=None):
"""
This static method does not respect LFRequest.proxy, it is not set in scope here
:param url_:
:param debug_:
:param die_on_error_:
:return:
"""
myrequest = request.Request(url=url_)
myresponses = []
try:
if (proxies_ is not None) and (len(proxies_) > 0):
# https://stackoverflow.com/a/59635684/11014343
opener = myrequest.build_opener(myrequest.ProxyHandler(proxies_))
myrequest.install_opener(opener)
myresponses.append(request.urlopen(myrequest))
return myresponses[0]
except urllib.error.HTTPError as error:
print_diagnostics(url_=url_,
request_=request,
responses_=myresponses,
error_=error,
debug_=debug_)
except urllib.error.URLError as uerror:
print_diagnostics(url_=url_,
request_=request,
responses_=myresponses,
error_=uerror,
debug_=debug_)
if die_on_error_:
exit(1)
return None
def print_diagnostics(url_=None, request_=None, responses_=None, error_=None, error_list_=None, debug_=False):
logger = logging.getLogger(__name__)
# logger.error("LFRequest::print_diagnostics: error_.__class__: %s"%error_.__class__)
# logger.error(pformat(error_))
if url_ is None:
logger.warning("WARNING LFRequest::print_diagnostics: url_ is None")
if request_ is None:
logger.warning("WARNING LFRequest::print_diagnostics: request_ is None")
if error_ is None:
logger.warning("WARNING LFRequest::print_diagnostics: error_ is None")
method = 'NA'
if hasattr(request_, 'method'):
method = request_.method
err_code = 0
err_reason = 'NA'
err_headers = []
err_full_url = url_
if hasattr(error_, 'code'):
err_code = error_.code
if hasattr(error_, 'reason'):
err_reason = error_.reason
if hasattr(error_, 'headers'):
err_headers = error_.headers
if hasattr(error_, 'get_full_url'):
err_full_url = error_.get_full_url()
xerrors = []
if err_code == 404:
xerrors.append("[%s HTTP %s] <%s> : %s" % (method, err_code, err_full_url, err_reason))
else:
if len(err_headers) > 0:
for headername in sorted(err_headers.keys()):
if headername.startswith("X-Error-"):
xerrors.append("%s: %s" % (headername, err_headers.get(headername)))
if len(xerrors) > 0:
logger.error(" = = LANforge Error Messages = =")
logger.error(" = = URL: %s" % err_full_url)
for xerr in xerrors:
logger.error(xerr)
if (error_list_ is not None) and isinstance(error_list_, list):
error_list_.append(xerr)
logger.error(" = = = = = = = = = = = = = = = =")
if error_.__class__ is urllib.error.HTTPError:
logger.debug("----- LFRequest: HTTPError: --------------------------------------------")
logger.debug("%s <%s> HTTP %s: %s" % (method, err_full_url, err_code, err_reason))
if err_code == 404:
if (error_list_ is not None) and isinstance(error_list_, list):
error_list_.append("[%s HTTP %s] <%s> : %s" % (method, err_code, err_full_url, err_reason))
else:
logger.debug(
" Content-type:[%s] Accept[%s]" % (request_.get_header('Content-type'), request_.get_header('Accept')))
if hasattr(request_, "data") and (request_.data is not None):
logger.debug(" Data:")
logger.debug(debug_printer.pformat(request_.data))
elif debug_:
logger.debug(" <no request data>")
if len(err_headers) > 0:
# the HTTPError is of type HTTPMessage a subclass of email.message
logger.debug(" Response Headers: ")
for headername in sorted(err_headers.keys()):
logger.debug(" %s: %s" % (headername, err_headers.get(headername)))
if len(responses_) > 0:
logger.debug("----- Response: --------------------------------------------------------")
logger.debug(debug_printer.pformat(responses_[0].reason))
logger.debug("------------------------------------------------------------------------")
return
if error_.__class__ is urllib.error.URLError:
logger.error("----- LFRequest: URLError: ---------------------------------------------")
logger.error("%s <%s> HTTP %s: %s" % (method, err_full_url, err_code, err_reason))
logger.error("------------------------------------------------------------------------")
# ~LFRequest