# -*- coding: utf-8 -*- # vStream https://github.com/Kodi-vStream/venom-xbmc-addons # from requests import Session, Request, HTTPError from resources.lib.comaddon import addon, dialog, VSlog, VSPath, isMatrix class cRequestHandler: REQUEST_TYPE_GET = 0 REQUEST_TYPE_POST = 1 def __init__(self, sUrl): self.__sUrl = sUrl self.__sRealUrl = '' self.__cType = 0 self.__aParamaters = {} self.__aParamatersLine = '' self.__aHeaderEntries = {} self.__Cookie = {} self.removeBreakLines(True) self.removeNewLines(True) self.__setDefaultHeader() self.__timeout = 30 self.__bRemoveNewLines = False self.__bRemoveBreakLines = False self.__sResponseHeader = '' self.BUG_SSL = False self.__enableDNS = False self.s = Session() self.redirects = True #Empeche les redirections def disableRedirect(self): self.redirects = False def removeNewLines(self, bRemoveNewLines): self.__bRemoveNewLines = bRemoveNewLines def removeBreakLines(self, bRemoveBreakLines): self.__bRemoveBreakLines = bRemoveBreakLines #Defini le type de requete #0 : pour un requete GET #1 : pour une requete POST def setRequestType(self, cType): self.__cType = cType #Permets de definir un timeout def setTimeout(self, valeur): self.__timeout = valeur #Ajouter un cookie dans le headers de la requete def addCookieEntry(self, sHeaderKey, sHeaderValue): aHeader = {sHeaderKey: sHeaderValue} self.__Cookie.update(aHeader) #Ajouter un elements dans le headers de la requete def addHeaderEntry(self, sHeaderKey, sHeaderValue): for sublist in list(self.__aHeaderEntries): if sHeaderKey in sublist: self.__aHeaderEntries.pop(sublist) if sHeaderKey == "Content-Length": sHeaderValue = str(sHeaderValue) aHeader = {sHeaderKey: sHeaderValue} self.__aHeaderEntries.update(aHeader) #Ajout un parametre dans la requete def addParameters(self, sParameterKey, mParameterValue): self.__aParamaters[sParameterKey] = mParameterValue #Ajoute une ligne de parametre def addParametersLine(self, mParameterValue): self.__aParamatersLine = mParameterValue # egg addMultipartFiled({'sess_id': sId, 'upload_type': 'url', 'srv_tmp_url': sTmp}) def addMultipartFiled(self, fields): mpartdata = MPencode(fields) self.__aParamatersLine = mpartdata[1] self.addHeaderEntry('Content-Type', mpartdata[0] ) self.addHeaderEntry('Content-Length', len(mpartdata[1])) # Je sais plus si elle gere les doublons def getResponseHeader(self): return self.__sResponseHeader # url after redirects def getRealUrl(self): return self.__sRealUrl def request(self): # Supprimee car deconne si url contient ' ' et '+' en meme temps # self.__sUrl = self.__sUrl.replace(' ', '+') return self.__callRequest() #Recupere les cookies de la requete def GetCookies(self): if not self.__sResponseHeader: return '' if 'Set-Cookie' in self.__sResponseHeader: import re c = self.__sResponseHeader.get('set-cookie') c2 = re.findall('(?:^|,) *([^;,]+?)=([^;,]+?);', c) if c2: cookies = '' for cook in c2: cookies = cookies + cook[0] + '=' + cook[1] + ';' cookies = cookies[:-1] return cookies return '' def __setDefaultHeader(self): self.addHeaderEntry('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0') self.addHeaderEntry('Accept-Language', 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3') self.addHeaderEntry('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7') def __callRequest(self): if self.__enableDNS: import socket self.save_getaddrinfo = socket.getaddrinfo socket.getaddrinfo = self.new_getaddrinfo if self.__aParamatersLine: sParameters = self.__aParamatersLine else: sParameters = self.__aParamaters if (self.__cType == cRequestHandler.REQUEST_TYPE_GET): if (len(sParameters) > 0): if (self.__sUrl.find('?') == -1): self.__sUrl = self.__sUrl + '?' + str(sParameters) sParameters = '' else: self.__sUrl = self.__sUrl + '&' + str(sParameters) sParameters = '' sContent = '' if self.__cType == cRequestHandler.REQUEST_TYPE_GET: method = "GET" else: method = "POST" try: _request = Request(method, self.__sUrl, headers=self.__aHeaderEntries) if method in ['POST', 'PATCH', 'PUT']: _request.data = sParameters if self.__Cookie: _request.cookies = self.__Cookie prepped = _request.prepare() self.s.headers.update(self.__aHeaderEntries) oResponse = self.s.send(prepped, timeout=self.__timeout, allow_redirects=self.redirects) self.__sResponseHeader = oResponse.headers self.__sRealUrl = oResponse.url sContent = oResponse.content #Necessaire pour Python 3 if isMatrix(): sContent = sContent.decode('unicode-escape') except HTTPError as e: if 'CERTIFICATE_VERIFY_FAILED' in str(e.reason) and self.BUG_SSL == False: self.BUG_SSL = True return self.__callRequest() elif 'getaddrinfo failed' in str(e.reason) and self.__enableDNS == False: # Retry with DNS only if addon is present import xbmcvfs if xbmcvfs.exists('special://home/addons/script.module.dnspython/'): self.__enableDNS = True return self.__callRequest() else: error_msg = addon().VSlang(30470) else: error_msg = "%s (%s),%s" % (addon().VSlang(30205), e.reason, self.__sUrl) dialog().VSerror(error_msg) sContent = '' if oResponse.status_code == 503: # Protected by cloudFlare ? from resources.lib import cloudflare if cloudflare.CheckIfActive(sContent): cookies = self.GetCookies() VSlog('Page protegee par cloudflare') CF = cloudflare.CloudflareBypass() sContent = CF.GetHtml(self.__sUrl, sContent, cookies, sParameters, oResponse.headers) self.__sRealUrl, self.__sResponseHeader = CF.GetReponseInfo() if not sContent: dialog().VSerror("%s (%d),%s" % (addon().VSlang(30205), oResponse.status_code, self.__sUrl)) if sContent: if (self.__bRemoveNewLines == True): sContent = sContent.replace("\n", "") sContent = sContent.replace("\r\t", "") if (self.__bRemoveBreakLines == True): sContent = sContent.replace(" ", "") if self.__enableDNS: socket.getaddrinfo = self.save_getaddrinfo self.__enableDNS = False return sContent def new_getaddrinfo(self, *args): try: import sys import dns.resolver path = VSPath('special://home/addons/script.module.dnspython/lib/').decode('utf-8') if path not in sys.path: sys.path.append(path) host = args[0] port = args[1] # Keep the domain only: http://example.com/foo/bar => example.com if "//" in host: host = host[host.find("//"):] if "/" in host: host = host[:host.find("/")] resolver = dns.resolver.Resolver(configure=False) # Résolveurs DNS ouverts: https://www.fdn.fr/actions/dns/ resolver.nameservers = ['80.67.169.12', '2001:910:800::12', '80.67.169.40', '2001:910:800::40'] answer = resolver.query(host, 'a') host_found = str(answer[0]) VSlog("new_getaddrinfo found host %s" % host_found) # Keep same return schema as socket.getaddrinfo (family, type, proto, canonname, sockaddr) return [(2, 1, 0, '', (host_found, port)), (2, 1, 0, '', (host_found, port))] except Exception as e: VSlog("new_getaddrinfo ERROR: {0}".format(e)) return self.save_getaddrinfo(*args) # ****************************************************************************** # from https://github.com/eliellis/mpart.py # ****************************************************************************** def MPencode(fields): import mimetypes random_boundary = __randy_boundary() content_type = "multipart/form-data, boundary=%s" % random_boundary form_data = [] if fields: for (key, value) in fields.iteritems(): if not hasattr(value, 'read'): itemstr = '--%s\r\nContent-Disposition: form-data; name="%s"\r\n\r\n%s\r\n' % (random_boundary, key, value) form_data.append(itemstr) elif hasattr(value, 'read'): with value: file_mimetype = mimetypes.guess_type(value.name)[0] if mimetypes.guess_type(value.name)[0] else 'application/octet-stream' itemstr = '--%s\r\nContent-Disposition: form-data; name="%s"; filename="%s"\r\nContent-Type: %s\r\n\r\n%s\r\n' % (random_boundary, key, value.name, file_mimetype, value.read()) form_data.append(itemstr) else: raise Exception(value, 'Field is neither a file handle or any other decodable type.') else: pass form_data.append('--%s--\r\n' % random_boundary) return content_type, ''.join(form_data) def __randy_boundary(length=10, reshuffle=False): import string import random character_string = string.letters + string.digits boundary_string = [] for i in range(0, length): rand_index = random.randint(0, len(character_string) - 1) boundary_string.append(character_string[rand_index]) if reshuffle: random.shuffle(boundary_string) else: pass return ''.join(boundary_string)