diff --git a/VERSION b/VERSION index e657a8d6..fc99cdc6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-30 14:45:39) dev +Version 2.0.9 (2012-10-01 15:54:19) dev diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index a4d527a6..6bd56b37 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -787,7 +787,7 @@ def edit_language(): _class='untranslated' if k==s else 'translated' - if len(key) <= 40: + if len(s) <= 40: elem = INPUT(_type='text', _name=name, value=s, _size=70,_class=_class) else: diff --git a/applications/welcome/views/generic.xml b/applications/welcome/views/generic.xml index 234b4055..b4a11d9e 100644 --- a/applications/welcome/views/generic.xml +++ b/applications/welcome/views/generic.xml @@ -1 +1 @@ -{{from gluon.serializers import xml}}{{=XML(xml(response._vars,quote=False))}} +{{from gluon.serializers import xml}}{{=XML(xml(response._vars,quote=False))}} diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 30ed9278..1202a2f2 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -358,20 +358,33 @@ OLD IMPLEMENTATION: return module """ +_base_environment_ = dict((k,getattr(html,k)) for k in html.__all__) +_base_environment_.update((k,getattr(validators,k)) for k in validators.__all__) +_base_environment_['__builtins__'] = __builtins__ +_base_environment_['HTTP'] = HTTP +_base_environment_['redirect'] = redirect +_base_environment_['DAL'] = DAL +_base_environment_['Field'] = Field +_base_environment_['SQLDB'] = SQLDB # for backward compatibility +_base_environment_['SQLField'] = SQLField # for backward compatibility +_base_environment_['SQLFORM'] = SQLFORM +_base_environment_['SQLTABLE'] = SQLTABLE +_base_environment_['LOAD'] = LOAD + def build_environment(request, response, session, store_current=True): """ Build the environment dictionary into which web2py files are executed. """ - h,v = html,validators - environment = dict((k,getattr(h,k)) for k in h.__all__) - environment.update((k,getattr(v, k)) for k in v.__all__) + #h,v = html,validators + environment = dict(_base_environment_) + if not request.env: request.env = Storage() # Enable standard conditional models (i.e., /*.py, /[controller]/*.py, and # /[controller]/[function]/*.py) response.models_to_run = [r'^\w+\.py$', r'^%s/\w+\.py$' % request.controller, r'^%s/%s/\w+\.py$' % (request.controller, request.function)] - + t = environment['T'] = translator(request) c = environment['cache'] = Cache(request) if store_current: @@ -389,27 +402,16 @@ def build_environment(request, response, session, store_current=True): __builtins__ = mybuiltin() else: __builtins__['__import__'] = __builtin__.__import__ ### WHY? - environment['__builtins__'] = __builtins__ - environment['HTTP'] = HTTP - environment['redirect'] = redirect environment['request'] = request environment['response'] = response environment['session'] = session - environment['DAL'] = DAL - environment['Field'] = Field - environment['SQLDB'] = SQLDB # for backward compatibility - environment['SQLField'] = SQLField # for backward compatibility - environment['SQLFORM'] = SQLFORM - environment['SQLTABLE'] = SQLTABLE - environment['LOAD'] = LOAD environment['local_import'] = \ - lambda name, reload=False, app=request.application:\ - local_import_aux(name,reload,app) + lambda name, reload=False, app=request.application:\ + local_import_aux(name,reload,app) BaseAdapter.set_folder(pjoin(request.folder, 'databases')) response._view_environment = copy.copy(environment) return environment - def save_pyc(filename): """ Bytecode compiles the file `filename` diff --git a/gluon/dal.py b/gluon/dal.py index d477f0c2..1a50c2d2 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -3261,6 +3261,12 @@ class FireBirdAdapter(BaseAdapter): def SUBSTRING(self,field,parameters): return 'SUBSTRING(%s from %s for %s)' % (self.expand(field), parameters[0], parameters[1]) + def CONTAINS(self, first, second): + if first.type.startswith('list:'): + key = '|'+str(second).replace('|','||').replace('%','%%')+'|' + return '(%s CONTAINING %s)' % (self.expand(first), + self.expand(key,'string')) + def _drop(self,table,mode): sequence_name = table._sequence_name return ['DROP TABLE %s %s;' % (table, mode), 'DROP GENERATOR %s;' % sequence_name] @@ -7375,8 +7381,8 @@ class Table(object): self._primarykey = args.get('primarykey', None) self._before_insert = [] - self._before_update = [lambda self,fs:self.delete_uploaded_files(fs)] - self._before_delete = [lambda self:self.delete_uploaded_files()] + self._before_update = [Set.delete_uploaded_files] + self._before_delete = [Set.delete_uploaded_files] self._after_insert = [] self._after_update = [] self._after_delete = [] diff --git a/gluon/rocket.py b/gluon/rocket.py index 05d6da6c..ebe44db8 100644 --- a/gluon/rocket.py +++ b/gluon/rocket.py @@ -2,6 +2,7 @@ # This file is part of the Rocket Web Server # Copyright (c) 2011 Timothy Farrell +# Modified by Massimo Di Pierro # Import System Modules import sys @@ -12,7 +13,7 @@ import platform import traceback # Define Constants -VERSION = '1.2.4' +VERSION = '1.2.5' SERVER_NAME = socket.gethostname() SERVER_SOFTWARE = 'Rocket %s' % VERSION HTTP_SERVER_SOFTWARE = '%s Python/%s' % (SERVER_SOFTWARE, sys.version.split(' ')[0]) @@ -1454,37 +1455,34 @@ class Worker(Thread): return req - def read_headers(self, sock_file): + def read_headers(self, sock_file, environ): try: - headers = dict() - lname = lval = '' + lname = None while True: - line = sock_file.readline() + l = sock_file.readline() if PY3K: try: - line = str(line, 'ISO-8859-1') + l = str(l, 'ISO-8859-1') except UnicodeDecodeError: - self.err_log.warning('Client sent invalid header: ' + repr(line)) - if line == '\r\n': - if lname: headers[str(lname)] = str(lval) + self.err_log.warning('Invalid request header: '+repr(l)) + + if l.strip() == '': break - elif line.strip() == '' or '\0' in line: - raise BadRequest("Empty line in hader") - elif line[0] in ' \t' and lname: + elif l[0] in ' \t' and lname: # Some headers take more than one line - lval += ' ' + line.strip() - elif ':' in line: - if lname: headers[str(lname)] = str(lval) - lname, lval = line.split(':', 1) - # HTTP header names are us-ascii encoded - lname = lname.strip().upper().replace('-', '_') + environ[lname] += ' ' + l.strip() + else: # HTTP header values are latin-1 encoded - lval = lval.strip() + l = l.split(':', 1) + # HTTP header names are us-ascii encoded + + lname = str('HTTP_'+l[0].strip().upper().replace('-', '_')) + lval = str(l[-1].strip()) + environ[lname] = lval + except socket.timeout: raise SocketTimeout("Socket timed out before request.") - return headers - class SocketTimeout(Exception): "Exception for when a socket times out between requests." pass @@ -1545,209 +1543,10 @@ class ChunkedReader(object): yield self.readline() def get_method(method): - - - methods = dict(wsgi=WSGIWorker, - fs=FileSystemWorker) + methods = dict(wsgi=WSGIWorker) return methods[method.lower()] # Monolithic build...end of module: rocket\worker.py -# Monolithic build...start of module: rocket\methods\__init__.py - -# Monolithic build...end of module: rocket\methods\__init__.py -# Monolithic build...start of module: rocket\methods\fs.py - -# Import System Modules -import os -import time -import mimetypes -from email.utils import formatdate -from wsgiref.headers import Headers -from wsgiref.util import FileWrapper -# Import Package Modules -# package imports removed in monolithic build - - -# Define Constants -CHUNK_SIZE = 2**16 # 64 Kilobyte chunks -HEADER_RESPONSE = '''HTTP/1.1 %s\r\n%s''' -INDEX_HEADER = '''\ - -Directory Index: %(path)s - - -

Directory Index: %(path)s

- - -''' -INDEX_ROW = '''''' -INDEX_FOOTER = '''
Directories
\r\n''' - -class LimitingFileWrapper(FileWrapper): - def __init__(self, limit=None, *args, **kwargs): - self.limit = limit - FileWrapper.__init__(self, *args, **kwargs) - - def read(self, amt): - if amt > self.limit: - amt = self.limit - self.limit -= amt - return FileWrapper.read(self, amt) - -class FileSystemWorker(Worker): - def __init__(self, *args, **kwargs): - """Builds some instance variables that will last the life of the - thread.""" - - Worker.__init__(self, *args, **kwargs) - - self.root = os.path.abspath(self.app_info['document_root']) - self.display_index = self.app_info['display_index'] - - def serve_file(self, filepath, headers): - filestat = os.stat(filepath) - self.size = filestat.st_size - modtime = time.strftime("%a, %d %b %Y %H:%M:%S GMT", - time.gmtime(filestat.st_mtime)) - self.headers.add_header('Last-Modified', modtime) - if headers.get('if_modified_since') == modtime: - # The browser cache is up-to-date, send a 304. - self.status = "304 Not Modified" - self.data = [] - return - - ct = mimetypes.guess_type(filepath)[0] - self.content_type = ct if ct else 'text/plain' - try: - f = open(filepath, 'rb') - self.headers['Pragma'] = 'cache' - self.headers['Cache-Control'] = 'private' - self.headers['Content-Length'] = str(self.size) - if self.etag: - self.headers.add_header('Etag', self.etag) - if self.expires: - self.headers.add_header('Expires', self.expires) - - try: - # Implement 206 partial file support. - start, end = headers['range'].split('-') - start = 0 if not start.isdigit() else int(start) - end = self.size if not end.isdigit() else int(end) - if self.size < end or start < 0: - self.status = "214 Unsatisfiable Range Requested" - self.data = FileWrapper(f, CHUNK_SIZE) - else: - f.seek(start) - self.data = LimitingFileWrapper(f, CHUNK_SIZE, limit=end) - self.status = "206 Partial Content" - except: - self.data = FileWrapper(f, CHUNK_SIZE) - except IOError: - self.status = "403 Forbidden" - - def serve_dir(self, pth, rpth): - def rel_path(path): - return os.path.normpath(path[len(self.root):] if path.startswith(self.root) else path) - - if not self.display_index: - self.status = '404 File Not Found' - return b('') - else: - self.content_type = 'text/html' - - dir_contents = [os.path.join(pth, x) for x in os.listdir(os.path.normpath(pth))] - dir_contents.sort() - - dirs = [rel_path(x)+'/' for x in dir_contents if os.path.isdir(x)] - files = [rel_path(x) for x in dir_contents if os.path.isfile(x)] - - self.data = [INDEX_HEADER % dict(path='/'+rpth)] - if rpth: - self.data += [INDEX_ROW % dict(name='(parent directory)', cls='dir parent', link='/'.join(rpth[:-1].split('/')[:-1]))] - self.data += [INDEX_ROW % dict(name=os.path.basename(x[:-1]), link=os.path.join(rpth, os.path.basename(x[:-1])).replace('\\', '/'), cls='dir') for x in dirs] - self.data += ['Files'] - self.data += [INDEX_ROW % dict(name=os.path.basename(x), link=os.path.join(rpth, os.path.basename(x)).replace('\\', '/'), cls='file') for x in files] - self.data += [INDEX_FOOTER] - self.headers['Content-Length'] = self.size = str(sum([len(x) for x in self.data])) - self.status = '200 OK' - - def run_app(self, conn): - self.status = "200 OK" - self.size = 0 - self.expires = None - self.etag = None - self.content_type = 'text/plain' - self.content_length = None - - if __debug__: - self.err_log.debug('Getting sock_file') - - # Build our file-like object - sock_file = conn.makefile('rb',BUF_SIZE) - request = self.read_request_line(sock_file) - if request['method'].upper() not in ('GET', ): - self.status = "501 Not Implemented" - - try: - # Get our file path - reader = self.read_headers(sock_file) - headers = dict((k.lower(),v) for k,v in reader.iteritems()) - rpath = request.get('path', '').lstrip('/') - filepath = os.path.join(self.root, rpath) - filepath = os.path.abspath(filepath) - if __debug__: - self.err_log.debug('Request for path: %s' % filepath) - - self.closeConnection = headers.get('connection', 'close').lower() == 'close' - self.headers = Headers([('Date', formatdate(usegmt=True)), - ('Server', HTTP_SERVER_SOFTWARE), - ('Connection', headers.get('connection', 'close')), - ]) - - if not filepath.lower().startswith(self.root.lower()): - # File must be within our root directory - self.status = "400 Bad Request" - self.closeConnection = True - elif not os.path.exists(filepath): - self.status = "404 File Not Found" - self.closeConnection = True - elif os.path.isdir(filepath): - self.serve_dir(filepath, rpath) - elif os.path.isfile(filepath): - self.serve_file(filepath, headers) - else: - # It exists but it's not a file or a directory???? - # What is it then? - self.status = "501 Not Implemented" - self.closeConnection = True - - h = self.headers - statcode, statstr = self.status.split(' ', 1) - statcode = int(statcode) - if statcode >= 400: - h.add_header('Content-Type', self.content_type) - self.data = [statstr] - - # Build our output headers - header_data = HEADER_RESPONSE % (self.status, str(h)) - - # Send the headers - if __debug__: - self.err_log.debug('Sending Headers: %s' % repr(header_data)) - self.conn.sendall(b(header_data)) - - for data in self.data: - self.conn.sendall(b(data)) - - if hasattr(self.data, 'close'): - self.data.close() - - finally: - if __debug__: - self.err_log.debug('Finally closing sock_file') - sock_file.close() - -# Monolithic build...end of module: rocket\methods\fs.py # Monolithic build...start of module: rocket\methods\wsgi.py # Import System Modules @@ -1815,16 +1614,15 @@ class WSGIWorker(Worker): environ = self.base_environ.copy() # Grab the headers - for k, v in self.read_headers(sock_file).items(): - environ[str('HTTP_'+k)] = v + self.read_headers(sock_file,environ) # Add CGI Variables - environ['REQUEST_METHOD'] = request['method'] - environ['PATH_INFO'] = request['path'] - environ['SERVER_PROTOCOL'] = request['protocol'] environ['SERVER_PORT'] = str(conn.server_port) environ['REMOTE_PORT'] = str(conn.client_port) environ['REMOTE_ADDR'] = str(conn.client_addr) + environ['REQUEST_METHOD'] = request['method'] + environ['PATH_INFO'] = request['path'] + environ['SERVER_PROTOCOL'] = request['protocol'] environ['QUERY_STRING'] = request['query_string'] if 'HTTP_CONTENT_LENGTH' in environ: environ['CONTENT_LENGTH'] = environ['HTTP_CONTENT_LENGTH']