109 lines
4.9 KiB
Python
109 lines
4.9 KiB
Python
import requests
|
|
import json
|
|
import logging
|
|
from requests.structures import CaseInsensitiveDict
|
|
from pyexecplugins.pyexecplugins import PyExecPlugin
|
|
|
|
class Plugin(PyExecPlugin):
|
|
name = "Http"
|
|
|
|
taskdef = {
|
|
"name" : "pyrest",
|
|
"description" : "Execute an HTTP request with pyrest worker",
|
|
"inputKeys" : ["url", "body", "contentType", "method", "accept", "headers", "connectionTimeout", "readTimeout"],
|
|
"outputKeys" : ["body", "status", "reason", "headers"],
|
|
"ownerEmail" : "m.lettere@gmail.com"
|
|
}
|
|
|
|
def __init__(self, data, config=None):
|
|
super().__init__(data, config)
|
|
self.method = data.get("method") or "get"
|
|
self.url = data.get("url")
|
|
self.headers = data.get("headers") or {}
|
|
self.headers = CaseInsensitiveDict(self.headers)
|
|
self.contenttype = self.headers.get("Content-Type")
|
|
self.accept = self.headers.get("Accept")
|
|
self.body = data.get("body")
|
|
self.params = data.get("params")
|
|
self.expect = data.get("expect")
|
|
self.fail = data.get("fail")
|
|
self.conntimeout = data.get("connection-timeout") or 5
|
|
self.readtimeout = data.get("read-timeout") or 10
|
|
self.notimeout = (data.get("no-timeout") in (True, "true", "True", "TRUE", 1, "1", "y", "Y", "yes", "YES")) or False
|
|
|
|
def adaptMultipart(self, parts):
|
|
req = {}
|
|
for p in parts:
|
|
part = parts[p]
|
|
if(type(part) == str):
|
|
req[p] = part
|
|
elif (type(part) == list and len(part) > 0 and len(part) <= 2):
|
|
if len(part) == 1:
|
|
req[p] = (p, part[0])
|
|
elif len(part) == 2 and part[1].find("json"):
|
|
req[p] = (p, json.dumps(part[0]), part[1])
|
|
else:
|
|
req[p] = (p, part[0], part[1])
|
|
else:
|
|
raise Exception("Unable to parse multipart request. For every key either single string or an array matching requests tuple format is expected. Got %s with length %d for key %s" % (type(part), len(part), p))
|
|
return req
|
|
|
|
def doRequest(self):
|
|
logging.getLogger("pyexec").debug("%s - %s - %s - %s",self.method, self.url, self.contenttype, self.accept)
|
|
if self.contenttype != None and self.contenttype.find("json") != -1:
|
|
self.request = requests.Request(self.method, self.url, headers=self.headers, json = self.body)
|
|
elif self.contenttype != None and self.contenttype.find("multipart/form-data") != -1:
|
|
self.headers.pop("content-type")
|
|
self.request = requests.Request(self.method, self.url, headers=self.headers, files = self.adaptMultipart(self.body))
|
|
elif self.contenttype != None and self.contenttype.find("text") != -1:
|
|
self.request = requests.Request(self.method, self.url, headers=self.headers, data = self.body.encode('utf-8'))
|
|
else:
|
|
self.request = requests.Request(self.method, self.url, headers=self.headers, data = self.body, params = self.params)
|
|
|
|
self.request = self.request.prepare()
|
|
if self.notimeout:
|
|
timeout = None
|
|
else:
|
|
timeout= (self.conntimeout, self.readtimeout)
|
|
|
|
logging.getLogger("pyexec").info("%s url=%s body=%s conntimeout=%d readtimeout=%d",self.method, self.request.url,self.body,self.conntimeout,self.readtimeout)
|
|
self.response = requests.Session().send(self.request, timeout=timeout)
|
|
return self.response
|
|
|
|
def computeStatus(self):
|
|
if self.fail == False:
|
|
return "COMPLETED"
|
|
elif self.expect == None:
|
|
return "COMPLETED" if self.response.ok else "FAILED"
|
|
else:
|
|
if type(self.expect) == list:
|
|
return "COMPLETED" if (self.response.status_code in self.expect) else "FAILED"
|
|
else:
|
|
return "COMPLETED" if (self.response.status_code == self.expect) else "FAILED"
|
|
|
|
def buildOutput(self, status):
|
|
hdrs = {}
|
|
for k in self.response.headers.keys(): hdrs[k] = self.response.headers[k]
|
|
|
|
logging.getLogger("pyexec").info("Response: {} {}".format(self.response.status_code, self.response.reason))
|
|
|
|
if hdrs.get("Content-Type") != None and hdrs["Content-Type"].find("json") != -1 or self.accept != None and self.accept.find("json") != -1:
|
|
outbody = self.response.json() if len(self.response.content) != 0 else None
|
|
else:
|
|
outbody = self.response.text
|
|
|
|
logging.getLogger("pyexec").debug("%s", outbody)
|
|
if status == "FAILED":
|
|
raise Exception("HTTP call failed with status {} ({}) - {}".format(self.response.status_code, self.response.reason, str(outbody)))
|
|
return {
|
|
"body" : outbody,
|
|
"headers" : hdrs,
|
|
"status" : self.response.status_code,
|
|
"reason" : self.response.reason
|
|
}
|
|
|
|
def execute(self):
|
|
self.doRequest()
|
|
status = self.computeStatus()
|
|
return self.buildOutput(status)
|