/usr/share/pyshared/paste/progress.py is in python-paste 1.7.5.1-4.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
# (c) 2005 Clark C. Evans
# This module is part of the Python Paste Project and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
# This code was written with funding by http://prometheusresearch.com
"""
Upload Progress Monitor
This is a WSGI middleware component which monitors the status of files
being uploaded. It includes a small query application which will return
a list of all files being uploaded by particular session/user.
>>> from paste.httpserver import serve
>>> from paste.urlmap import URLMap
>>> from paste.auth.basic import AuthBasicHandler
>>> from paste.debug.debugapp import SlowConsumer, SimpleApplication
>>> # from paste.progress import *
>>> realm = 'Test Realm'
>>> def authfunc(username, password):
... return username == password
>>> map = URLMap({})
>>> ups = UploadProgressMonitor(map, threshold=1024)
>>> map['/upload'] = SlowConsumer()
>>> map['/simple'] = SimpleApplication()
>>> map['/report'] = UploadProgressReporter(ups)
>>> serve(AuthBasicHandler(ups, realm, authfunc))
serving on...
.. note::
This is experimental, and will change in the future.
"""
import time
from paste.wsgilib import catch_errors
DEFAULT_THRESHOLD = 1024 * 1024 # one megabyte
DEFAULT_TIMEOUT = 60*5 # five minutes
ENVIRON_RECEIVED = 'paste.bytes_received'
REQUEST_STARTED = 'paste.request_started'
REQUEST_FINISHED = 'paste.request_finished'
class _ProgressFile(object):
"""
This is the input-file wrapper used to record the number of
``paste.bytes_received`` for the given request.
"""
def __init__(self, environ, rfile):
self._ProgressFile_environ = environ
self._ProgressFile_rfile = rfile
self.flush = rfile.flush
self.write = rfile.write
self.writelines = rfile.writelines
def __iter__(self):
environ = self._ProgressFile_environ
riter = iter(self._ProgressFile_rfile)
def iterwrap():
for chunk in riter:
environ[ENVIRON_RECEIVED] += len(chunk)
yield chunk
return iter(iterwrap)
def read(self, size=-1):
chunk = self._ProgressFile_rfile.read(size)
self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
return chunk
def readline(self):
chunk = self._ProgressFile_rfile.readline()
self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
return chunk
def readlines(self, hint=None):
chunk = self._ProgressFile_rfile.readlines(hint)
self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
return chunk
class UploadProgressMonitor(object):
"""
monitors and reports on the status of uploads in progress
Parameters:
``application``
This is the next application in the WSGI stack.
``threshold``
This is the size in bytes that is needed for the
upload to be included in the monitor.
``timeout``
This is the amount of time (in seconds) that a upload
remains in the monitor after it has finished.
Methods:
``uploads()``
This returns a list of ``environ`` dict objects for each
upload being currently monitored, or finished but whose time
has not yet expired.
For each request ``environ`` that is monitored, there are several
variables that are stored:
``paste.bytes_received``
This is the total number of bytes received for the given
request; it can be compared with ``CONTENT_LENGTH`` to
build a percentage complete. This is an integer value.
``paste.request_started``
This is the time (in seconds) when the request was started
as obtained from ``time.time()``. One would want to format
this for presentation to the user, if necessary.
``paste.request_finished``
This is the time (in seconds) when the request was finished,
canceled, or otherwise disconnected. This is None while
the given upload is still in-progress.
TODO: turn monitor into a queue and purge queue of finished
requests that have passed the timeout period.
"""
def __init__(self, application, threshold=None, timeout=None):
self.application = application
self.threshold = threshold or DEFAULT_THRESHOLD
self.timeout = timeout or DEFAULT_TIMEOUT
self.monitor = []
def __call__(self, environ, start_response):
length = environ.get('CONTENT_LENGTH', 0)
if length and int(length) > self.threshold:
# replace input file object
self.monitor.append(environ)
environ[ENVIRON_RECEIVED] = 0
environ[REQUEST_STARTED] = time.time()
environ[REQUEST_FINISHED] = None
environ['wsgi.input'] = \
_ProgressFile(environ, environ['wsgi.input'])
def finalizer(exc_info=None):
environ[REQUEST_FINISHED] = time.time()
return catch_errors(self.application, environ,
start_response, finalizer, finalizer)
return self.application(environ, start_response)
def uploads(self):
return self.monitor
class UploadProgressReporter(object):
"""
reports on the progress of uploads for a given user
This reporter returns a JSON file (for use in AJAX) listing the
uploads in progress for the given user. By default, this reporter
uses the ``REMOTE_USER`` environment to compare between the current
request and uploads in-progress. If they match, then a response
record is formed.
``match()``
This member function can be overriden to provide alternative
matching criteria. It takes two environments, the first
is the current request, the second is a current upload.
``report()``
This member function takes an environment and builds a
``dict`` that will be used to create a JSON mapping for
the given upload. By default, this just includes the
percent complete and the request url.
"""
def __init__(self, monitor):
self.monitor = monitor
def match(self, search_environ, upload_environ):
if search_environ.get('REMOTE_USER', None) == \
upload_environ.get('REMOTE_USER', 0):
return True
return False
def report(self, environ):
retval = { 'started': time.strftime("%Y-%m-%d %H:%M:%S",
time.gmtime(environ[REQUEST_STARTED])),
'finished': '',
'content_length': environ.get('CONTENT_LENGTH'),
'bytes_received': environ[ENVIRON_RECEIVED],
'path_info': environ.get('PATH_INFO',''),
'query_string': environ.get('QUERY_STRING','')}
finished = environ[REQUEST_FINISHED]
if finished:
retval['finished'] = time.strftime("%Y:%m:%d %H:%M:%S",
time.gmtime(finished))
return retval
def __call__(self, environ, start_response):
body = []
for map in [self.report(env) for env in self.monitor.uploads()
if self.match(environ, env)]:
parts = []
for k, v in map.items():
v = str(v).replace("\\", "\\\\").replace('"', '\\"')
parts.append('%s: "%s"' % (k, v))
body.append("{ %s }" % ", ".join(parts))
body = "[ %s ]" % ", ".join(body)
start_response("200 OK", [('Content-Type', 'text/plain'),
('Content-Length', len(body))])
return [body]
__all__ = ['UploadProgressMonitor', 'UploadProgressReporter']
if "__main__" == __name__:
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
|