From 80582daaa0997dccba37e8cae4bec9dfa3ba324b Mon Sep 17 00:00:00 2001 From: JusticeN Date: Wed, 5 Sep 2018 14:17:33 +0200 Subject: [PATCH 1/5] changing the anyserver.py to make it run with py3 actually fixing the issue #1993 i have created. i tested it successfuly with the command python3 anyserver.py -s tornado -i 127.0.0.1 -p 80 -l --- anyserver.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/anyserver.py b/anyserver.py index b935a1ed..261dd422 100644 --- a/anyserver.py +++ b/anyserver.py @@ -212,16 +212,16 @@ def mongrel2_handler(application, conn, debug=False): while True: if debug: - print "WAITING FOR REQUEST" + print("WAITING FOR REQUEST") # receive a request req = conn.recv() if debug: - print "REQUEST BODY: %r\n" % req.body + print("REQUEST BODY: %r\n" % req.body) if req.is_disconnect(): if debug: - print "DISCONNECT" + print("DISCONNECT") continue # effectively ignore the disconnect from the client # Set a couple of environment attributes a.k.a. header attributes @@ -247,7 +247,7 @@ def mongrel2_handler(application, conn, debug=False): environ['wsgi.input'] = req.body if debug: - print "ENVIRON: %r\n" % environ + print("ENVIRON: %r\n" % environ) # SimpleHandler needs file-like stream objects for # requests, errors and responses @@ -282,10 +282,10 @@ def mongrel2_handler(application, conn, debug=False): # return the response if debug: - print "RESPONSE: %r\n" % response + print("RESPONSE: %r\n" % response) if errors: if debug: - print "ERRORS: %r" % errors + print("ERRORS: %r" % errors) data = "%s\r\n\r\n%s" % (data, errors) conn.reply_http( req, data, code=code, status=status, headers=headers) @@ -355,8 +355,8 @@ def main(): dest='workers', help='number of workers number') (options, args) = parser.parse_args() - print 'starting %s on %s:%s...' % ( - options.server, options.ip, options.port) + print('starting %s on %s:%s...' % ( + options.server, options.ip, options.port)) run(options.server, options.ip, options.port, logging=options.logging, profiler=options.profiler_dir, options=options) From 9364aa2036dd84459ebc327cda406cb99083b1f5 Mon Sep 17 00:00:00 2001 From: Donald McClymont Date: Wed, 5 Sep 2018 23:34:05 +0100 Subject: [PATCH 2/5] Support for compiled apps on python 3.7 and above - marshal_header_size increased to 16 for those cases - tested by compiling and running welcome app on py 2.7,3.6 and 3.7 --- gluon/compileapp.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 0d61afb3..dd7aca00 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -15,7 +15,7 @@ Note: import re import fnmatch -import os +import os, sys import copy import random from gluon._compat import builtin, PY2, unicodeT, to_native, to_bytes, iteritems, basestring, reduce, xrange, long, reload @@ -52,7 +52,10 @@ is_gae = settings.global_settings.web2py_runtime_gae is_jython = settings.global_settings.is_jython pjoin = os.path.join -marshal_header_size = 8 if PY2 else 12 +if PY2: + marshal_header_size = 8 +else: + marshal_header_size = 16 if sys.version_info[1] >= 7 else 12 TEST_CODE = \ r""" From 6e0da9cea7c2ed652ec645cbbfedaf423b474af9 Mon Sep 17 00:00:00 2001 From: Faelysse Date: Thu, 6 Sep 2018 14:46:07 +0200 Subject: [PATCH 3/5] HTTP header date made independent of locale, fixes #1997 --- gluon/main.py | 5 ++--- gluon/streamer.py | 3 ++- gluon/utils.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/gluon/main.py b/gluon/main.py index 9867c87b..e634de37 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -31,7 +31,7 @@ from gluon._compat import Cookie, urllib2 from gluon.fileutils import abspath, write_file from gluon.settings import global_settings -from gluon.utils import web2py_uuid +from gluon.utils import web2py_uuid, unlocalised_http_header_date from gluon.admin import add_path_first, create_missing_folders, create_missing_app_folders from gluon.globals import current @@ -199,8 +199,7 @@ def serve_controller(request, response, session): ('Content-Type', contenttype('.' + request.extension)), ('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'), - ('Expires', time.strftime('%a, %d %b %Y %H:%M:%S GMT', - time.gmtime())), + ('Expires', unlocalised_http_header_date(time.gmtime())), ('Pragma', 'no-cache')] for key, value in default_headers: response.headers.setdefault(key, value) diff --git a/gluon/streamer.py b/gluon/streamer.py index 288c71b3..2872f7a5 100644 --- a/gluon/streamer.py +++ b/gluon/streamer.py @@ -16,6 +16,7 @@ import time import re import errno from gluon.http import HTTP +from gluon.utils import unlocalised_http_header_date from gluon.contenttype import contenttype from gluon._compat import PY2 @@ -74,7 +75,7 @@ def stream_file_or_304_or_206( stat_file = os.stat(static_file) fsize = stat_file[stat.ST_SIZE] modified = stat_file[stat.ST_MTIME] - mtime = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(modified)) + mtime = unlocalised_http_header_date(time.gmtime(modified)) headers.setdefault('Content-Type', contenttype(static_file)) headers.setdefault('Last-Modified', mtime) headers.setdefault('Pragma', 'cache') diff --git a/gluon/utils.py b/gluon/utils.py index ea738047..c3e5207f 100644 --- a/gluon/utils.py +++ b/gluon/utils.py @@ -462,3 +462,51 @@ def local_html_escape(data, quote=False): data = data.replace(b'"', b""") data = data.replace(b'\'', b"'") return data + + +def unlocalised_http_header_date(data): + """ + Converts input datetime to format defined by RFC 7231, section 7.1.1.1 + + Previously, %a and %b formats were used for weekday and month names, but + those are not locale-safe. uWSGI requires latin1-encodable headers and + for example in cs_CS locale, fourth day in week is not encodable in latin1, + as it's "Čt". + + Example output: Sun, 06 Nov 1994 08:49:37 GMT + """ + + short_weekday = { + "0": "Sun", + "1": "Mon", + "2": "Tue", + "3": "Wed", + "4": "Thu", + "5": "Fri", + "6": "Sat", + }.get(time.strftime("%w", data)) + + day_of_month = time.strftime("%d", data) + + short_month = { + "01": "Jan", + "02": "Feb", + "03": "Mar", + "04": "Apr", + "05": "May", + "06": "Jun", + "07": "Jul", + "08": "Aug", + "09": "Sep", + "10": "Oct", + "11": "Nov", + "12": "Dec", + }.get(time.strftime("%m", data)) + + year_and_time = time.strftime("%Y %H:%M:%S GMT") + + return "{}, {} {} {}".format( + short_weekday, + day_of_month, + short_month, + year_and_time) From 55a2f4a6b26ea93334b720dbc4420425fb9046c2 Mon Sep 17 00:00:00 2001 From: Mirko Galimberti Date: Thu, 6 Sep 2018 14:58:03 +0200 Subject: [PATCH 4/5] Fixes request_reset_password w/ custom userfield --- gluon/tools.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gluon/tools.py b/gluon/tools.py index 5cc4bf40..16d6ce2b 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -3447,7 +3447,8 @@ class Auth(AuthAPI): if log is DEFAULT: log = self.messages['reset_password_log'] userfield = self.settings.login_userfield or 'username' \ - if 'username' in table_user.fields else 'email' + if self.settings.login_userfield or 'username' \ + in table_user.fields else 'email' if userfield == 'email': table_user.email.requires = [ IS_EMAIL(error_message=self.messages.invalid_email), @@ -3456,11 +3457,11 @@ class Auth(AuthAPI): if not self.settings.email_case_sensitive: table_user.email.requires.insert(0, IS_LOWER()) else: - table_user.username.requires = [ - IS_IN_DB(self.db, table_user.username, + table_user[userfield].requires = [ + IS_IN_DB(self.db, table_user[userfield], error_message=self.messages.invalid_username)] if not self.settings.username_case_sensitive: - table_user.username.requires.insert(0, IS_LOWER()) + table_user[userfield].requires.insert(0, IS_LOWER()) form = SQLFORM(table_user, fields=[userfield], From 09c8b5ecedca4926c978ad4f5a93071b2ba9abb2 Mon Sep 17 00:00:00 2001 From: Mirko Galimberti Date: Fri, 7 Sep 2018 10:23:07 +0200 Subject: [PATCH 5/5] skip requires on custom userfield --- gluon/tools.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gluon/tools.py b/gluon/tools.py index 16d6ce2b..0910b6c4 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -3456,12 +3456,12 @@ class Auth(AuthAPI): error_message=self.messages.invalid_email)] if not self.settings.email_case_sensitive: table_user.email.requires.insert(0, IS_LOWER()) - else: - table_user[userfield].requires = [ - IS_IN_DB(self.db, table_user[userfield], + elif userfield == 'username': + table_user.username.requires = [ + IS_IN_DB(self.db, table_user.username, error_message=self.messages.invalid_username)] if not self.settings.username_case_sensitive: - table_user[userfield].requires.insert(0, IS_LOWER()) + table_user.username.requires.insert(0, IS_LOWER()) form = SQLFORM(table_user, fields=[userfield],