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)