diff options
author | Marc Abramowitz <marc@marc-abramowitz.com> | 2015-04-30 17:39:24 -0700 |
---|---|---|
committer | Marc Abramowitz <marc@marc-abramowitz.com> | 2015-04-30 17:39:24 -0700 |
commit | fa100c92c06d3a8a61a0dda1a2e06018437b09c6 (patch) | |
tree | a1cc50f93fbf257685c3849e03496c5e33949281 /paste/exceptions/reporter.py | |
download | paste-git-fa100c92c06d3a8a61a0dda1a2e06018437b09c6.tar.gz |
test_wsgirequest_charset: Use UTF-8 instead of iso-8859-1test_wsgirequest_charset_use_UTF-8_instead_of_iso-8859-1
because it seems that the defacto standard for encoding URIs is to use UTF-8.
I've been reading about url encoding and it seems like perhaps using an
encoding other than UTF-8 is very non-standard and not well-supported (this
test is trying to use `iso-8859-1`).
From http://en.wikipedia.org/wiki/Percent-encoding
> For a non-ASCII character, it is typically converted to its byte sequence in
> UTF-8, and then each byte value is represented as above.
> The generic URI syntax mandates that new URI schemes that provide for the
> representation of character data in a URI must, in effect, represent
> characters from the unreserved set without translation, and should convert
> all other characters to bytes according to UTF-8, and then percent-encode
> those values. This requirement was introduced in January 2005 with the
> publication of RFC 3986
From http://tools.ietf.org/html/rfc3986:
> Non-ASCII characters must first be encoded according to UTF-8 [STD63], and
> then each octet of the corresponding UTF-8 sequence must be percent-encoded
> to be represented as URI characters. URI producing applications must not use
> percent-encoding in host unless it is used to represent a UTF-8 character
> sequence.
From http://tools.ietf.org/html/rfc3987:
> Conversions from URIs to IRIs MUST NOT use any character encoding other than
> UTF-8 in steps 3 and 4, even if it might be possible to guess from the
> context that another character encoding than UTF-8 was used in the URI. For
> example, the URI "http://www.example.org/r%E9sum%E9.html" might with some
> guessing be interpreted to contain two e-acute characters encoded as
> iso-8859-1. It must not be converted to an IRI containing these e-acute
> characters. Otherwise, in the future the IRI will be mapped to
> "http://www.example.org/r%C3%A9sum%C3%A9.html", which is a different URI from
> "http://www.example.org/r%E9sum%E9.html".
See issue #7, which I think this at least partially fixes.
Diffstat (limited to 'paste/exceptions/reporter.py')
-rw-r--r-- | paste/exceptions/reporter.py | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/paste/exceptions/reporter.py b/paste/exceptions/reporter.py new file mode 100644 index 0000000..7c0c266 --- /dev/null +++ b/paste/exceptions/reporter.py @@ -0,0 +1,141 @@ +# (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 + +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +import smtplib +import time +try: + from socket import sslerror +except ImportError: + sslerror = None +from paste.exceptions import formatter + +class Reporter(object): + + def __init__(self, **conf): + for name, value in conf.items(): + if not hasattr(self, name): + raise TypeError( + "The keyword argument %s was not expected" + % name) + setattr(self, name, value) + self.check_params() + + def check_params(self): + pass + + def format_date(self, exc_data): + return time.strftime('%c', exc_data.date) + + def format_html(self, exc_data, **kw): + return formatter.format_html(exc_data, **kw) + + def format_text(self, exc_data, **kw): + return formatter.format_text(exc_data, **kw) + +class EmailReporter(Reporter): + + to_addresses = None + from_address = None + smtp_server = 'localhost' + smtp_username = None + smtp_password = None + smtp_use_tls = False + subject_prefix = '' + + def report(self, exc_data): + msg = self.assemble_email(exc_data) + server = smtplib.SMTP(self.smtp_server) + if self.smtp_use_tls: + server.ehlo() + server.starttls() + server.ehlo() + if self.smtp_username and self.smtp_password: + server.login(self.smtp_username, self.smtp_password) + server.sendmail(self.from_address, + self.to_addresses, msg.as_string()) + try: + server.quit() + except sslerror: + # sslerror is raised in tls connections on closing sometimes + pass + + def check_params(self): + if not self.to_addresses: + raise ValueError("You must set to_addresses") + if not self.from_address: + raise ValueError("You must set from_address") + if isinstance(self.to_addresses, (str, unicode)): + self.to_addresses = [self.to_addresses] + + def assemble_email(self, exc_data): + short_html_version = self.format_html( + exc_data, show_hidden_frames=False) + long_html_version = self.format_html( + exc_data, show_hidden_frames=True) + text_version = self.format_text( + exc_data, show_hidden_frames=False) + msg = MIMEMultipart() + msg.set_type('multipart/alternative') + msg.preamble = msg.epilogue = '' + text_msg = MIMEText(text_version) + text_msg.set_type('text/plain') + text_msg.set_param('charset', 'ASCII') + msg.attach(text_msg) + html_msg = MIMEText(short_html_version) + html_msg.set_type('text/html') + # @@: Correct character set? + html_msg.set_param('charset', 'UTF-8') + html_long = MIMEText(long_html_version) + html_long.set_type('text/html') + html_long.set_param('charset', 'UTF-8') + msg.attach(html_msg) + msg.attach(html_long) + subject = '%s: %s' % (exc_data.exception_type, + formatter.truncate(str(exc_data.exception_value))) + msg['Subject'] = self.subject_prefix + subject + msg['From'] = self.from_address + msg['To'] = ', '.join(self.to_addresses) + return msg + +class LogReporter(Reporter): + + filename = None + show_hidden_frames = True + + def check_params(self): + assert self.filename is not None, ( + "You must give a filename") + + def report(self, exc_data): + text = self.format_text( + exc_data, show_hidden_frames=self.show_hidden_frames) + f = open(self.filename, 'a') + try: + f.write(text + '\n' + '-'*60 + '\n') + finally: + f.close() + +class FileReporter(Reporter): + + file = None + show_hidden_frames = True + + def check_params(self): + assert self.file is not None, ( + "You must give a file object") + + def report(self, exc_data): + text = self.format_text( + exc_data, show_hidden_frames=self.show_hidden_frames) + self.file.write(text + '\n' + '-'*60 + '\n') + +class WSGIAppReporter(Reporter): + + def __init__(self, exc_data): + self.exc_data = exc_data + + def __call__(self, environ, start_response): + start_response('500 Server Error', [('Content-type', 'text/html')]) + return [formatter.format_html(self.exc_data)] |