summaryrefslogtreecommitdiffstats
path: root/pyload/network
diff options
context:
space:
mode:
Diffstat (limited to 'pyload/network')
-rw-r--r--pyload/network/Browser.py23
-rw-r--r--pyload/network/CookieJar.py1
-rw-r--r--pyload/network/HTTPChunk.py24
-rw-r--r--pyload/network/HTTPDownload.py13
-rw-r--r--pyload/network/HTTPRequest.py18
-rw-r--r--pyload/network/JsEngine.py4
-rw-r--r--pyload/network/RequestFactory.py9
-rw-r--r--pyload/network/XDCCRequest.py12
8 files changed, 104 insertions, 0 deletions
diff --git a/pyload/network/Browser.py b/pyload/network/Browser.py
index 89341ff25..1c0596ccc 100644
--- a/pyload/network/Browser.py
+++ b/pyload/network/Browser.py
@@ -9,6 +9,7 @@ from pyload.network.HTTPDownload import HTTPDownload
class Browser(object):
__slots__ = ("log", "options", "bucket", "cj", "_size", "http", "dl")
+
def __init__(self, bucket=None, options={}):
self.log = getLogger("log")
@@ -26,6 +27,7 @@ class Browser(object):
if hasattr(self, "http"): self.http.close()
self.http = HTTPRequest(self.cj, self.options)
+
def setLastURL(self, val):
self.http.lastURL = val
@@ -35,17 +37,22 @@ class Browser(object):
code = property(lambda self: self.http.code)
cookieJar = property(lambda self: self.cj)
+
def setCookieJar(self, cj):
self.cj = cj
self.http.cj = cj
@property
+
+
def speed(self):
if self.dl:
return self.dl.speed
return 0
@property
+
+
def size(self):
if self._size:
return self._size
@@ -54,30 +61,38 @@ class Browser(object):
return 0
@property
+
+
def arrived(self):
if self.dl:
return self.dl.arrived
return 0
@property
+
+
def percent(self):
if not self.size: return 0
return (self.arrived * 100) / self.size
+
def clearCookies(self):
if self.cj:
self.cj.clear()
self.http.clearCookies()
+
def clearReferer(self):
self.http.lastURL = None
+
def abortDownloads(self):
self.http.abort = True
if self.dl:
self._size = self.dl.size
self.dl.abort = True
+
def httpDownload(self, url, filename, get={}, post={}, ref=True, cookies=True, chunks=1, resume=False,
progressNotify=None, disposition=False):
""" this can also download ftp """
@@ -91,14 +106,17 @@ class Browser(object):
return name
+
def load(self, *args, **kwargs):
""" retrieves page """
return self.http.load(*args, **kwargs)
+
def putHeader(self, name, value):
""" add a header to the request """
self.http.putHeader(name, value)
+
def addAuth(self, pwd):
"""Adds user and pw for http auth
@@ -107,20 +125,25 @@ class Browser(object):
self.options["auth"] = pwd
self.renewHTTPRequest() #we need a new request
+
def removeAuth(self):
if "auth" in self.options: del self.options["auth"]
self.renewHTTPRequest()
+
def setOption(self, name, value):
"""Adds an option to the request, see HTTPRequest for existing ones"""
self.options[name] = value
+
def deleteOption(self, name):
if name in self.options: del self.options[name]
+
def clearHeaders(self):
self.http.clearHeaders()
+
def close(self):
""" cleanup """
if hasattr(self, "http"):
diff --git a/pyload/network/CookieJar.py b/pyload/network/CookieJar.py
index a2b302776..35d7fa6ef 100644
--- a/pyload/network/CookieJar.py
+++ b/pyload/network/CookieJar.py
@@ -21,6 +21,7 @@ class CookieJar(Cookie.SimpleCookie):
def getCookie(self, name):
return self[name].value
+
def setCookie(self, domain, name, value, path="/", exp=None, secure="FALSE"):
self[name] = value
self[name]["domain"] = domain
diff --git a/pyload/network/HTTPChunk.py b/pyload/network/HTTPChunk.py
index 41752b940..5395b7bda 100644
--- a/pyload/network/HTTPChunk.py
+++ b/pyload/network/HTTPChunk.py
@@ -17,12 +17,14 @@ class WrongFormat(Exception):
class ChunkInfo(object):
+
def __init__(self, name):
self.name = unicode(name)
self.size = 0
self.resume = False
self.chunks = []
+
def __repr__(self):
ret = "ChunkInfo: %s, %s\n" % (self.name, self.size)
for i, c in enumerate(self.chunks):
@@ -30,15 +32,19 @@ class ChunkInfo(object):
return ret
+
def setSize(self, size):
self.size = int(size)
+
def addChunk(self, name, range):
self.chunks.append((name, range))
+
def clear(self):
self.chunks = []
+
def createChunks(self, chunks):
self.clear()
chunk_size = self.size / chunks
@@ -62,6 +68,8 @@ class ChunkInfo(object):
fh.close()
@staticmethod
+
+
def load(name):
fs_name = fs_encode("%s.chunks" % name)
if not exists(fs_name):
@@ -93,21 +101,26 @@ class ChunkInfo(object):
fh.close()
return ci
+
def remove(self):
fs_name = fs_encode("%s.chunks" % self.name)
if exists(fs_name): remove(fs_name)
+
def getCount(self):
return len(self.chunks)
+
def getChunkName(self, index):
return self.chunks[index][0]
+
def getChunkRange(self, index):
return self.chunks[index][1]
class HTTPChunk(HTTPRequest):
+
def __init__(self, id, parent, range=None, resume=False):
self.id = id
self.p = parent # HTTPDownload instance
@@ -136,13 +149,17 @@ class HTTPChunk(HTTPRequest):
self.sleep = 0.000
self.lastSize = 0
+
def __repr__(self):
return "<HTTPChunk id=%d, size=%d, arrived=%d>" % (self.id, self.size, self.arrived)
@property
+
+
def cj(self):
return self.p.cj
+
def getHandle(self):
""" returns a Curl handle ready to use for perform/multiperform """
@@ -188,6 +205,7 @@ class HTTPChunk(HTTPRequest):
return self.c
+
def writeHeader(self, buf):
self.header += buf
#@TODO forward headers?, this is possibly unneeeded, when we just parse valid 200 headers
@@ -202,6 +220,7 @@ class HTTPChunk(HTTPRequest):
self.headerParsed = True
+
def writeBody(self, buf):
#ignore BOM, it confuses unrar
if not self.BOMChecked:
@@ -263,25 +282,30 @@ class HTTPChunk(HTTPRequest):
self.headerParsed = True
+
def stop(self):
"""The download will not proceed after next call of writeBody"""
self.range = [0, 0]
self.size = 0
+
def resetRange(self):
""" Reset the range, so the download will load all data available """
self.range = None
+
def setRange(self, range):
self.range = range
self.size = range[1] - range[0]
+
def flushFile(self):
""" flush and close file """
self.fp.flush()
fsync(self.fp.fileno()) #make sure everything was written to disk
self.fp.close() #needs to be closed, or merging chunks will fail
+
def close(self):
""" closes everything, unusable after this """
if self.fp: self.fp.close()
diff --git a/pyload/network/HTTPDownload.py b/pyload/network/HTTPDownload.py
index 0d331ca99..89e594640 100644
--- a/pyload/network/HTTPDownload.py
+++ b/pyload/network/HTTPDownload.py
@@ -59,19 +59,26 @@ class HTTPDownload(object):
self.progress = progress
@property
+
+
def speed(self):
last = [sum(x) for x in self.lastSpeeds if x]
return (sum(self.speeds) + sum(last)) / (1 + len(last))
@property
+
+
def arrived(self):
return sum([c.arrived for c in self.chunks])
@property
+
+
def percent(self):
if not self.size: return 0
return (self.arrived * 100) / self.size
+
def _copyChunks(self):
init = fs_encode(self.info.getChunkName(0)) #initial chunk name
@@ -104,6 +111,7 @@ class HTTPDownload(object):
move(init, fs_encode(self.filename))
self.info.remove() #remove info file
+
def download(self, chunks=1, resume=False):
""" returns new filename or None """
@@ -132,6 +140,7 @@ class HTTPDownload(object):
if self.nameDisposition and self.disposition: return self.nameDisposition
return None
+
def _download(self, chunks, resume):
if not resume:
self.info.clear()
@@ -280,15 +289,18 @@ class HTTPDownload(object):
self._copyChunks()
+
def updateProgress(self):
if self.progress:
self.progress(self.percent)
+
def findChunk(self, handle):
""" linear search to find a chunk (should be ok since chunk size is usually low) """
for chunk in self.chunks:
if chunk.c == handle: return chunk
+
def closeChunk(self, chunk):
try:
self.m.remove_handle(chunk.c)
@@ -297,6 +309,7 @@ class HTTPDownload(object):
finally:
chunk.close()
+
def close(self):
""" cleanup """
for chunk in self.chunks:
diff --git a/pyload/network/HTTPRequest.py b/pyload/network/HTTPRequest.py
index fe7e26c48..3e5903df3 100644
--- a/pyload/network/HTTPRequest.py
+++ b/pyload/network/HTTPRequest.py
@@ -28,6 +28,7 @@ bad_headers = range(400, 404) + range(405, 418) + range(500, 506)
class BadHeader(Exception):
+
def __init__(self, code, content=""):
Exception.__init__(self, "Bad server response: %s %s" % (code, responses[int(code)]))
self.code = code
@@ -35,6 +36,7 @@ class BadHeader(Exception):
class HTTPRequest(object):
+
def __init__(self, cookies=None, options=None):
self.c = pycurl.Curl()
self.rep = StringIO()
@@ -58,6 +60,7 @@ class HTTPRequest(object):
self.log = getLogger("log")
+
def initHandle(self):
""" sets common options to curl handle """
self.c.setopt(pycurl.FOLLOWLOCATION, 1)
@@ -87,6 +90,7 @@ class HTTPRequest(object):
"Keep-Alive: 300",
"Expect:"])
+
def setInterface(self, options):
interface, proxy, ipv6 = options["interface"], options["proxies"], options["ipv6"]
@@ -119,11 +123,13 @@ class HTTPRequest(object):
if "timeout" in options:
self.c.setopt(pycurl.LOW_SPEED_TIME, options["timeout"])
+
def addCookies(self):
""" put cookies from curl handle to cj """
if self.cj:
self.cj.addCookies(self.c.getinfo(pycurl.INFO_COOKIELIST))
+
def getCookies(self):
""" add cookies from cj to curl handle """
if self.cj:
@@ -131,9 +137,11 @@ class HTTPRequest(object):
self.c.setopt(pycurl.COOKIELIST, c)
return
+
def clearCookies(self):
self.c.setopt(pycurl.COOKIELIST, "")
+
def setRequestContext(self, url, get, post, referer, cookies, multipart=False):
""" sets everything needed for the request """
@@ -171,6 +179,7 @@ class HTTPRequest(object):
self.c.setopt(pycurl.COOKIEJAR, "")
self.getCookies()
+
def load(self, url, get={}, post={}, referer=True, cookies=True, just_header=False, multipart=False, decode=False, follow_location=True, save_cookies=True):
""" load and returns a given page """
@@ -212,6 +221,7 @@ class HTTPRequest(object):
return rep
+
def verifyHeader(self):
""" raise an exceptions on bad headers """
code = int(self.c.getinfo(pycurl.RESPONSE_CODE))
@@ -220,10 +230,12 @@ class HTTPRequest(object):
raise BadHeader(code, self.getResponse())
return code
+
def checkHeader(self):
""" check if header indicates failure"""
return int(self.c.getinfo(pycurl.RESPONSE_CODE)) not in bad_headers
+
def getResponse(self):
""" retrieve response from string io """
if self.rep is None:
@@ -234,6 +246,7 @@ class HTTPRequest(object):
self.rep = StringIO()
return value
+
def decodeResponse(self, rep):
""" decode with correct encoding, relies on header """
header = self.header.splitlines()
@@ -269,6 +282,7 @@ class HTTPRequest(object):
return rep
+
def write(self, buf):
""" writes response """
if self.rep.tell() > 1000000 or self.abort:
@@ -283,16 +297,20 @@ class HTTPRequest(object):
else:
self.rep.write(buf)
+
def writeHeader(self, buf):
""" writes header """
self.header += buf
+
def putHeader(self, name, value):
self.headers.append("%s: %s" % (name, value))
+
def clearHeaders(self):
self.headers = []
+
def close(self):
""" cleanup, unusable after this """
self.rep.close()
diff --git a/pyload/network/JsEngine.py b/pyload/network/JsEngine.py
index c64e8c490..bcf6ae0e2 100644
--- a/pyload/network/JsEngine.py
+++ b/pyload/network/JsEngine.py
@@ -33,6 +33,8 @@ class JsEngine(object):
@classmethod
+
+
def find(cls):
""" Check if there is any engine available """
return [E for E in ENGINES if E.find()]
@@ -120,6 +122,8 @@ class AbstractEngine(object):
@classmethod
+
+
def find(cls):
""" Check if the engine is available """
try:
diff --git a/pyload/network/RequestFactory.py b/pyload/network/RequestFactory.py
index 579eafea7..5f8e7e206 100644
--- a/pyload/network/RequestFactory.py
+++ b/pyload/network/RequestFactory.py
@@ -11,6 +11,7 @@ from pyload.network.CookieJar import CookieJar
from pyload.network.XDCCRequest import XDCCRequest
class RequestFactory(object):
+
def __init__(self, core):
self.lock = Lock()
self.core = core
@@ -18,9 +19,11 @@ class RequestFactory(object):
self.updateBucket()
self.cookiejars = {}
+
def iface(self):
return self.core.config["download"]["interface"]
+
def getRequest(self, pluginName, account=None, type="HTTP"):
self.lock.acquire()
@@ -38,12 +41,14 @@ class RequestFactory(object):
self.lock.release()
return req
+
def getHTTPRequest(self, **kwargs):
""" returns a http request, dont forget to close it ! """
options = self.getOptions()
options.update(kwargs) # submit kwargs as additional options
return HTTPRequest(CookieJar(None), options)
+
def getURL(self, *args, **kwargs):
""" see HTTPRequest for argument list """
cj = None
@@ -65,6 +70,7 @@ class RequestFactory(object):
return rep
+
def getCookieJar(self, pluginName, account=None):
if (pluginName, account) in self.cookiejars:
return self.cookiejars[(pluginName, account)]
@@ -73,6 +79,7 @@ class RequestFactory(object):
self.cookiejars[(pluginName, account)] = cj
return cj
+
def getProxies(self):
""" returns a proxy list for the request classes """
if not self.core.config["proxy"]["proxy"]:
@@ -99,12 +106,14 @@ class RequestFactory(object):
"password": pw,
}
+
def getOptions(self):
"""returns options needed for pycurl"""
return {"interface": self.iface(),
"proxies": self.getProxies(),
"ipv6": self.core.config["download"]["ipv6"]}
+
def updateBucket(self):
""" set values in the bucket according to settings"""
if not self.core.config["download"]["limit_speed"]:
diff --git a/pyload/network/XDCCRequest.py b/pyload/network/XDCCRequest.py
index c49f418c4..a4813e039 100644
--- a/pyload/network/XDCCRequest.py
+++ b/pyload/network/XDCCRequest.py
@@ -16,6 +16,7 @@ from pyload.plugin.Plugin import Abort
class XDCCRequest(object):
+
def __init__(self, timeout=30, proxies={}):
self.proxies = proxies
@@ -27,6 +28,7 @@ class XDCCRequest(object):
self.abort = False
+
def createSocket(self):
# proxytype = None
# proxy = None
@@ -46,6 +48,7 @@ class XDCCRequest(object):
return socket.socket()
+
def download(self, ip, port, filename, irc, progress=None):
ircbuffer = ""
@@ -109,6 +112,7 @@ class XDCCRequest(object):
return filename
+
def _keepAlive(self, sock, *readbuffer):
fdset = select([sock], [], [], 0)
if sock not in fdset[0]:
@@ -124,21 +128,29 @@ class XDCCRequest(object):
if first[0] == "PING":
sock.send("PONG %s\r\n" % first[1])
+
def abortDownloads(self):
self.abort = True
@property
+
+
def size(self):
return self.filesize
@property
+
+
def arrived(self):
return self.recv
@property
+
+
def percent(self):
if not self.filesize: return 0
return (self.recv * 100) / self.filesize
+
def close(self):
pass