617 if content_type.startswith('text/') and ';charset=' not in content_type: |
617 if content_type.startswith('text/') and ';charset=' not in content_type: |
618 content_type += ';charset=' + (encoding or self.encoding) |
618 content_type += ';charset=' + (encoding or self.encoding) |
619 self.set_header('content-type', content_type) |
619 self.set_header('content-type', content_type) |
620 if filename: |
620 if filename: |
621 header = ['attachment'] |
621 header = ['attachment'] |
|
622 unicode_filename = None |
622 try: |
623 try: |
623 filename = filename.encode('ascii') |
624 ascii_filename = filename.encode('ascii') |
624 header.append('filename=' + filename) |
|
625 except UnicodeEncodeError: |
625 except UnicodeEncodeError: |
626 # fallback filename for very old browser |
626 # fallback filename for very old browser |
627 header.append('filename=' + filename.encode('ascii', 'ignore')) |
627 unicode_filename = filename |
|
628 ascii_filename = filename.encode('ascii', 'ignore') |
|
629 # escape " and \ |
|
630 # see http://greenbytes.de/tech/tc2231/#attwithfilenameandextparamescaped |
|
631 ascii_filename = ascii_filename.replace('\x5c', r'\\').replace('"', r'\"') |
|
632 header.append('filename="%s"' % ascii_filename) |
|
633 if unicode_filename is not None: |
628 # encoded filename according RFC5987 |
634 # encoded filename according RFC5987 |
629 filename = urllib.quote(filename.encode('utf-8'), '') |
635 urlquoted_filename = urllib.quote(unicode_filename.encode('utf-8'), '') |
630 header.append("filename*=utf-8''" + filename) |
636 header.append("filename*=utf-8''" + urlquoted_filename) |
631 self.set_header('content-disposition', ';'.join(header)) |
637 self.set_header('content-disposition', ';'.join(header)) |
632 |
638 |
633 # high level methods for HTML headers management ########################## |
639 # high level methods for HTML headers management ########################## |
634 |
640 |
635 def add_onload(self, jscode): |
641 def add_onload(self, jscode): |