Merge branch 'master' of https://github.com/Raihid/qutebrowser into Raihid-master

This commit is contained in:
Florian Bruhin 2016-12-01 13:23:01 +01:00
commit d668a1b6d6
4 changed files with 197 additions and 179 deletions

View File

@ -32,6 +32,7 @@ import email.generator
import email.encoders import email.encoders
import email.mime.multipart import email.mime.multipart
import email.message import email.message
import quopri
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
@ -138,6 +139,22 @@ def _check_rel(element):
return any(rel in rels for rel in must_have) return any(rel in rels for rel in must_have)
def _encode_quopri_mhtml(msg):
"""Encode the message's payload in quoted-printable.
Substitute for quopri's default 'encode_quopri' method, which needlessly
encodes all spaces and tabs, instead of only those at the end on the
line.
Args:
msg: Email message to quote.
"""
orig = msg.get_payload(decode=True)
encdata = quopri.encodestring(orig, quotetabs=False)
msg.set_payload(encdata)
msg['Content-Transfer-Encoding'] = 'quoted-printable'
MHTMLPolicy = email.policy.default.clone(linesep='\r\n', max_line_length=0) MHTMLPolicy = email.policy.default.clone(linesep='\r\n', max_line_length=0)
@ -146,7 +163,7 @@ E_BASE64 = email.encoders.encode_base64
# Encode the file using MIME quoted-printable encoding. # Encode the file using MIME quoted-printable encoding.
E_QUOPRI = email.encoders.encode_quopri E_QUOPRI = _encode_quopri_mhtml
class MHTMLWriter: class MHTMLWriter:

View File

@ -8,143 +8,125 @@ Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
<html><head> <html><head>
=20=20=20=20=20=20=20=20<meta=20http-equiv=3D"Content-Type"=20content=3D"te= <meta http-equiv=3D"Content-Type" content=3D"text/html;charset=3DUT=
xt/html;charset=3DUTF-8"> F-8">
=20=20=20=20=20=20=20=20<title>qutebrowser=20mhtml=20test</title> <title>qutebrowser mhtml test</title>
=20=20=20=20 =20
=20=20=20=20=20=20=20=20<!--=20make=20sure=20<style>=20tags=20are=20parsed= <!-- make sure <style> tags are parsed -->
=20=20--> <style>
=20=20=20=20=20=20=20=20<style> body {
=20=20=20=20=20=20=20=20body=20{ background-image: url('Background.png');
=20=20=20=20=20=20=20=20=20=20=20=20background-image:=20url('Background.png= background-repeat: repeat-x;
'); font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-=
=20=20=20=20=20=20=20=20=20=20=20=20background-repeat:=20repeat-x; serif;
=20=20=20=20=20=20=20=20=20=20=20=20font-family:=20"Open=20Sans","Helvetica= font-size: 120%;
=20Neue",Helvetica,Arial,sans-serif; }
=20=20=20=20=20=20=20=20=20=20=20=20font-size:=20120%; img#banner {
=20=20=20=20=20=20=20=20} display: block;
=20=20=20=20=20=20=20=20img#banner=20{ margin: 20px auto;
=20=20=20=20=20=20=20=20=20=20=20=20display:=20block; }
=20=20=20=20=20=20=20=20=20=20=20=20margin:=2020px=20auto; </style>
=20=20=20=20=20=20=20=20} =20
=20=20=20=20=20=20=20=20</style> <!-- make sure external css is included -->
=20=20=20=20=20=20=20=20 <link rel=3D"stylesheet" href=3D"base.css">
=20=20=20=20=20=20=20=20<!--=20make=20sure=20external=20css=20is=20included= =20
=20--> <!-- don't parse non-CSS styles -->
=20=20=20=20=20=20=20=20<link=20rel=3D"stylesheet"=20href=3D"base.css"> <style rel=3D"stylesheet" type=3D"text/qss">
=20=20=20=20=20=20=20=20 @import "actually-it's-css";
=20=20=20=20=20=20=20=20<!--=20don't=20parse=20non-CSS=20styles=20--> </style>
=20=20=20=20=20=20=20=20<style=20rel=3D"stylesheet"=20type=3D"text/qss"> =20
=20=20=20=20=20=20=20=20@import=20"actually-it's-css"; <!-- make sure icons are included -->
=20=20=20=20=20=20=20=20</style> <link rel=3D"icon" href=3D"favicon.png">
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<!--=20make=20sure=20icons=20are=20included=20--> <!-- make sure authors are NOT included -->
=20=20=20=20=20=20=20=20<link=20rel=3D"icon"=20href=3D"favicon.png"> <link rel=3D"author" href=3D"author.html">
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<!--=20make=20sure=20authors=20are=20NOT=20included= <!-- make sure scripts are included -->
=20--> <script type=3D"text/javascript" src=3D"script.js"></script>
=20=20=20=20=20=20=20=20<link=20rel=3D"author"=20href=3D"author.html"> =20
=20=20=20=20=20=20=20=20 <!-- ...but don't crash on scripts without src -->
=20=20=20=20=20=20=20=20<!--=20make=20sure=20scripts=20are=20included=20--> <script>
=20=20=20=20=20=20=20=20<script=20type=3D"text/javascript"=20src=3D"script.= var l =3D 1+1;
js"></script> </script>
=20=20=20=20=20=20=20=20 </head>
=20=20=20=20=20=20=20=20=20<!--=20...but=20don't=20crash=20on=20scripts=20w= <body>
ithout=20src=20--> <!-- make sure images are included -->
=20=20=20=20=20=20=20=20<script> <img src=3D"Banner.png" id=3D"banner">
=20=20=20=20=20=20=20=20=20=20=20=20var=20l=20=3D=201+1; =20
=20=20=20=20=20=20=20=20</script> <h1>Welcome to the qutebrowser mhtml test page</h1>
=20=20=20=20</head> =20
=20=20=20=20<body> <div class=3D"dyk">
=20=20=20=20=20=20=20=20<!--=20make=20sure=20images=20are=20included=20--> ...that the word <em>qutebrowser</em> is a word play on Qt, the
=20=20=20=20=20=20=20=20<img=20src=3D"Banner.png"=20id=3D"banner"> framework the browser is built with?
=20=20=20=20=20=20=20=20 </div>
=20=20=20=20=20=20=20=20<h1>Welcome=20to=20the=20qutebrowser=20mhtml=20test= =20
=20page</h1> <h2>What is this page?</h2>
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<div=20class=3D"dyk"> <p>This page is a test-case for the mhtml download feature of
=20=20=20=20=20=20=20=20...that=20the=20word=20<em>qutebrowser</em>=20is=20= qutebrowser. Under normal circumstances, you won't see this page, e=
a=20word=20play=20on=20Qt,=20the xcept
=20=20=20=20=20=20=20=20framework=20the=20browser=20is=20built=20with? if you're a qutebrowser developer <em>or</em> you're attending one =
=20=20=20=20=20=20=20=20</div> of
=20=20=20=20=20=20=20=20 The-Compiler's pytest demos.</p>
=20=20=20=20=20=20=20=20<h2>What=20is=20this=20page?</h2> =20
=20=20=20=20=20=20=20=20 <div class=3D"dyk">
=20=20=20=20=20=20=20=20<p>This=20page=20is=20a=20test-case=20for=20the=20m= ...that this page was once a monstrosity with <em>"this weird pixel=
html=20download=20feature=20of ated
=20=20=20=20=20=20=20=20qutebrowser.=20Under=20normal=20circumstances,=20yo= globe with the geocities-like background"</em>? You can find the old
u=20won't=20see=20this=20page,=20except page in the old commits and indeed, it was quite atrocious. But hey,
=20=20=20=20=20=20=20=20if=20you're=20a=20qutebrowser=20developer=20<em>or<= every browser needs a globe...
/em>=20you're=20attending=20one=20of </div>
=20=20=20=20=20=20=20=20The-Compiler's=20pytest=20demos.</p> =20
=20=20=20=20=20=20=20=20 <p>This page references other assets and when the page is downloade=
=20=20=20=20=20=20=20=20<div=20class=3D"dyk"> d,
=20=20=20=20=20=20=20=20...that=20this=20page=20was=20once=20a=20monstrosit= qutebrowser checks if each asset was downloaded. If some assets are
y=20with=20<em>"this=20weird=20pixelated missing, the test fails and the poor developers have to search for =
=20=20=20=20=20=20=20=20globe=20with=20the=20geocities-like=20background"</= the
em>?=20You=20can=20find=20the=20old error.</p>
=20=20=20=20=20=20=20=20page=20in=20the=20old=20commits=20and=20indeed,=20i= =20
t=20was=20quite=20atrocious.=20But=20hey, <h2>Can I contribute to qutebrowser?</h2>
=20=20=20=20=20=20=20=20every=20browser=20needs=20a=20globe... =20
=20=20=20=20=20=20=20=20</div> <p>Yes!</p>
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<p>This=20page=20references=20other=20assets=20and= <div class=3D"dyk">
=20when=20the=20page=20is=20downloaded, ...that qutebrowser is free software? Free as in <em>free beer</em>=
=20=20=20=20=20=20=20=20qutebrowser=20checks=20if=20each=20asset=20was=20do= and
wnloaded.=20If=20some=20assets=20are <em>free speech</em>! Isn't that great?
=20=20=20=20=20=20=20=20missing,=20the=20test=20fails=20and=20the=20poor=20= </div>
developers=20have=20to=20search=20for=20the =20
=20=20=20=20=20=20=20=20error.</p> <h2>...and how?</h2>
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<h2>Can=20I=20contribute=20to=20qutebrowser?</h2> <p>See <a href=3D"https://github.com/The-Compiler/qutebrowser/blob/=
=20=20=20=20=20=20=20=20 master/CONTRIBUTING.asciidoc">
=20=20=20=20=20=20=20=20<p>Yes!</p> here</a> for more information.</p>
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<div=20class=3D"dyk"> <h2>More useless trivia!</h2>
=20=20=20=20=20=20=20=20...that=20qutebrowser=20is=20free=20software?=20Fre= =20
e=20as=20in=20<em>free=20beer</em>=20and <div class=3D"dyk">
=20=20=20=20=20=20=20=20<em>free=20speech</em>!=20Isn't=20that=20great? ...that the font in the header is Comic Sans?
=20=20=20=20=20=20=20=20</div> </div>
=20=20=20=20=20=20=20=20 =20
=20=20=20=20=20=20=20=20<h2>...and=20how?</h2> <div class=3D"dyk">
=20=20=20=20=20=20=20=20 ...the IRC channel for qutebrowser is <code>#qutebrowser</code> on
=20=20=20=20=20=20=20=20<p>See=20<a=20href=3D"https://github.com/The-Compil= irc.freenode.net
er/qutebrowser/blob/master/CONTRIBUTING.asciidoc"> </div>
=20=20=20=20=20=20=20=20here</a>=20for=20more=20information.</p> =20
=20=20=20=20=20=20=20=20 <div class=3D"dyk">
=20=20=20=20=20=20=20=20<h2>More=20useless=20trivia!</h2> ...the area of a circle is =CF=80*r<sup>2</sup>?
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 </div>
=20=20=20=20=20=20=20=20<div=20class=3D"dyk"> =20
=20=20=20=20=20=20=20=20...that=20the=20font=20in=20the=20header=20is=20Com= <p>To make this page a bit useful, I've included a chessboard, so y=
ic=20Sans? ou
=20=20=20=20=20=20=20=20</div> can play chess. Just turn your screen 90 degrees, such that it form=
=20=20=20=20=20=20=20=20 s a
=20=20=20=20=20=20=20=20<div=20class=3D"dyk"> flat, horizontal surface (you can skip this step if you're using a
=20=20=20=20=20=20=20=20...the=20IRC=20channel=20for=20qutebrowser=20is=20<= tablet). Next, zoom the page until it fits your needs. Enjoy your r=
code>#qutebrowser</code>=20on ound
=20=20=20=20=20=20=20=20irc.freenode.net of chess!</p>
=20=20=20=20=20=20=20=20</div> <!-- make sure inline styles are parsed -->
=20=20=20=20=20=20=20=20 <div style=3D"background-image: url('Inline.png'); background-repea=
=20=20=20=20=20=20=20=20<div=20class=3D"dyk"> t: no-repeat; width: 160px; height: 160px;"></div>
=20=20=20=20=20=20=20=20...the=20area=20of=20a=20circle=20is=20=CF=80*r<sup= =20
>2</sup>?
=20=20=20=20=20=20=20=20</div>
=20=20=20=20=20=20=20=20
=20=20=20=20=20=20=20=20<p>To=20make=20this=20page=20a=20bit=20useful,=20I'=
ve=20included=20a=20chessboard,=20so=20you
=20=20=20=20=20=20=20=20can=20play=20chess.=20Just=20turn=20your=20screen=
=2090=20degrees,=20such=20that=20it=20forms=20a
=20=20=20=20=20=20=20=20flat,=20horizontal=20surface=20(you=20can=20skip=20=
this=20step=20if=20you're=20using=20a
=20=20=20=20=20=20=20=20tablet).=20Next,=20zoom=20the=20page=20until=20it=
=20fits=20your=20needs.=20Enjoy=20your=20round
=20=20=20=20=20=20=20=20of=20chess!</p>
=20=20=20=20=20=20=20=20<!--=20make=20sure=20inline=20styles=20are=20parsed=
=20-->
=20=20=20=20=20=20=20=20<div=20style=3D"background-image:=20url('Inline.png=
');=20background-repeat:=20no-repeat;=20width:=20160px;=20height:=20160px;"=
></div>
=20=20=20=20
</body></html> </body></html>
-----=_qute-5314618b-e51d-46e1-9598-103536e86b59 -----=_qute-5314618b-e51d-46e1-9598-103536e86b59
@ -709,35 +691,33 @@ MIME-Version: 1.0
Content-Type: text/css; charset=utf-8 Content-Type: text/css; charset=utf-8
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
@import=20'external-in-extern.css'; @import 'external-in-extern.css';
/*=20We=20want=20to=20make=20sure=20that=20assets=20referenced=20in=20exter= /* We want to make sure that assets referenced in external css files are
nal=20css=20files=20are * properly included
=20*=20properly=20included */
=20*/ div.dyk {
div.dyk=20{ /* Did you know? */
=20=20=20=20/*=20Did=20you=20know?=20*/ background-image: url('DYK.png');
=20=20=20=20background-image:=20url('DYK.png'); background-repeat: no-repeat;
=20=20=20=20background-repeat:=20no-repeat; /* Image is 128px wide */
=20=20=20=20/*=20Image=20is=20128px=20wide=20*/ min-height: 128px;
=20=20=20=20min-height:=20128px; padding-left: 148px;
=20=20=20=20padding-left:=20148px; margin-top: 10px;
=20=20=20=20margin-top:=2010px; margin-bottom: 10px;
=20=20=20=20margin-bottom:=2010px; border: 2px solid #474747;
=20=20=20=20border:=202px=20solid=20#474747; border-radius: 64px;
=20=20=20=20border-radius:=2064px;
} }
=20=20=20=20 =20
-----=_qute-5314618b-e51d-46e1-9598-103536e86b59 -----=_qute-5314618b-e51d-46e1-9598-103536e86b59
Content-Location: http://localhost:1337/data/downloads/mhtml/complex/external-in-extern.css Content-Location: http://localhost:1337/data/downloads/mhtml/complex/external-in-extern.css
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/css; charset=utf-8 Content-Type: text/css; charset=utf-8
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
/*=20Just=20making=20sure=20that=20more=20than=20one=20level=20of=20externa= /* Just making sure that more than one level of external css is included */
l=20css=20is=20included=20*/ h1, h2, h3, h4, h5, h6 {
h1,=20h2,=20h3,=20h4,=20h5,=20h6=20{ color: #0A396E;
=20=20=20=20color:=20#0A396E; border-bottom: 1px dotted #474747;
=20=20=20=20border-bottom:=201px=20dotted=20#474747;
} }
-----=_qute-5314618b-e51d-46e1-9598-103536e86b59 -----=_qute-5314618b-e51d-46e1-9598-103536e86b59
Content-Location: http://localhost:1337/data/downloads/mhtml/complex/favicon.png Content-Location: http://localhost:1337/data/downloads/mhtml/complex/favicon.png

View File

@ -7,14 +7,13 @@ MIME-Version: 1.0
Content-Type: text/html; charset="UTF-8" Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
<!DOCTYPE=20html><html><head> <!DOCTYPE html><html><head>
=20=20=20=20=20=20=20=20<meta=20charset=3D"utf-8"> <meta charset=3D"utf-8">
=20=20=20=20=20=20=20=20<title>Simple=20MHTML=20test</title> <title>Simple MHTML test</title>
=20=20=20=20</head> </head>
=20=20=20=20<body> <body>
=20=20=20=20=20=20=20=20<a=20href=3D"/">normal=20link=20to=20another=20page= <a href=3D"/">normal link to another page</a>
</a> =20
=20=20=20=20
</body></html> </body></html>
-----=_qute-6d584056-b1e4-4882-91e6-d4a6d23adb67-- -----=_qute-6d584056-b1e4-4882-91e6-d4a6d23adb67--

View File

@ -87,7 +87,7 @@ def test_quoted_printable_umlauts(checker):
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Die=20s=FC=DFe=20H=FCndin=20l=E4uft=20in=20die=20H=F6hle=20des=20B=E4ren Die s=FC=DFe H=FCndin l=E4uft in die H=F6hle des B=E4ren
-----=_qute-UUID-- -----=_qute-UUID--
""") """)
@ -128,7 +128,7 @@ def test_file_encoded_as_base64(checker):
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Image=20file=20attached Image file attached
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://a.example.com/image.png Content-Location: http://a.example.com/image.png
MIME-Version: 1.0 MIME-Version: 1.0
@ -175,56 +175,56 @@ def test_files_appear_sorted(checker):
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
root=20file root file
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://a.example.com/ Content-Location: http://a.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20a file a
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://b.example.com/ Content-Location: http://b.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20b file b
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://g.example.com/ Content-Location: http://g.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20g file g
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://h.example.com/ Content-Location: http://h.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20h file h
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://i.example.com/ Content-Location: http://i.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20i file i
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://t.example.com/ Content-Location: http://t.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20t file t
-----=_qute-UUID -----=_qute-UUID
Content-Location: http://z.example.com/ Content-Location: http://z.example.com/
MIME-Version: 1.0 MIME-Version: 1.0
Content-Type: text/plain Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20z file z
-----=_qute-UUID-- -----=_qute-UUID--
""") """)
@ -251,7 +251,7 @@ def test_empty_content_type(checker):
Content-Location: http://example.com/file Content-Location: http://example.com/file
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
file=20content file content
-----=_qute-UUID-- -----=_qute-UUID--
""") """)
@ -283,6 +283,28 @@ def test_css_url_scanner(monkeypatch, has_cssutils, inline, style,
assert urls == expected_urls assert urls == expected_urls
def test_quoted_printable_spaces(checker):
content = b' ' * 100
writer = mhtml.MHTMLWriter(root_content=content,
content_location='localhost',
content_type='text/plain')
writer.write_to(checker.fp)
checker.expect("""
Content-Type: multipart/related; boundary="---=_qute-UUID"
MIME-Version: 1.0
-----=_qute-UUID
Content-Location: localhost
MIME-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable
{}=
{}=20
-----=_qute-UUID--
""".format(' ' * 75, ' ' * 24))
class TestNoCloseBytesIO: class TestNoCloseBytesIO:
def test_fake_close(self): def test_fake_close(self):