Safari按原样呈现HTML

Zim*_*m3r 9 safari http

当我加载一个html页面时,我有一个5个字符串,大约相隔一秒.

<br>1</br>
...... 1 second ......
<br>2</br>
...... 1 second ......
<br>3</br>
...... 1 second ......
<br>4</br>
...... 1 second ......
<br>5</br>
...... 1 second ......

--- end request ---
Run Code Online (Sandbox Code Playgroud)

Chromium和Firefox都会加载并显示第一个br,然后显示下一个br.(但Firefox需要内容编码).但在请求结束之前,Safari拒绝显示任何标记.

铬似乎只是这样做.

Firefox首先需要确定内容编码https://bugzilla.mozilla.org/show_bug.cgi?id=647203

但Safari似乎只是拒绝.是否需要不同的响应代码或标头?我尝试将内容类型明确设置为text/html.没工作.

我已经在Wireshark中确认字符串是分开发送的,即它们不会被缓存并立即发送.

我也确认如果我通过localhost或我使用我的公共IP地址会发生这种情况.

我已经尝试了内容长度并保持活着,前者只是自动关闭请求,后者似乎没有效果.

Wireshark的标题和回应

Firefox(工作)

GET /pe HTTP/1.1
Host: 127.0.01:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Tue, 10 Nov 2015 17:10:20 GMT
Connection: keep-alive
Content-Type: text/html; charset=utf-8
Server: TwistedWeb/13.2.0

1f
<html>
<title>PE</title>
<body>
2e

<br> This is the 1th time I've written. </br>
2e

<br> This is the 2th time I've written. </br>
2e

<br> This is the 3th time I've written. </br>
2e

<br> This is the 4th time I've written. </br>
2e

<br> This is the 5th time I've written. </br>
8

</body>
8

</html>
0
Run Code Online (Sandbox Code Playgroud)

Safari(不工作)

GET /pe HTTP/1.1
Host: 127.0.0.01:8080
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/601.1.56 (KHTML, like Gecko) Version/9.0 Safari/601.1.56
Accept-Language: en-us
DNT: 1
Connection: keep-alive

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Tue, 10 Nov 2015 17:12:55 GMT
Connection: keep-alive
Content-Type: text/html; charset=utf-8
Server: TwistedWeb/13.2.0

1f
<html>
<title>PE</title>
<body>
2e

<br> This is the 1th time I've written. </br>
2e

<br> This is the 2th time I've written. </br>
2e

<br> This is the 3th time I've written. </br>
2e

<br> This is the 4th time I've written. </br>
2e

<br> This is the 5th time I've written. </br>
8

</body>
8

</html>
0
Run Code Online (Sandbox Code Playgroud)

演示

import twisted
from twisted.python import log
import sys

log.startLogging(sys.stdout)
from twisted.web.server import Site, NOT_DONE_YET
from twisted.web.resource import Resource
from twisted.internet import reactor



class PersistantExample(Resource):
    '''Gives an example of a persistant request'''
    # does not exist on Safari until stopping browser / ending connection

    isLeaf = True
    def render_GET(self, request):
        log.msg("Ooooh a render request")
        # schedule the reoccuring thing (this could be something else like a deferred result)

        reactor.callLater(1.1, self.keeps_going, request, 0) # 1.1 seconds just to show it can take floats

        # firefox require the char set see https://bugzilla.mozilla.org/show_bug.cgi?id=647203
        request.responseHeaders.addRawHeader("Content-Type",
        "text/html; charset=utf-8") # set the MIME header (charset needed for firefox)

        # this will cause the connection to keep only open for x length
        # (only helpful if the length is known, also does NOT make it render right away)
        # request.responseHeaders.addRawHeader("Content-Length", "150")

        request.write("<html>\n<title>PE</title>\n<body>")
        return NOT_DONE_YET


    def keeps_going(self, request, i):
        log.msg("I'm going again....")
        i = i + 1
        request.write("\n<br> This is the %sth time I've written. <br>" % i) ## probably not best to use <br> tag

        if i < 5:
            reactor.callLater(1.1, self.keeps_going, request, i) # 1.1 seconds just to show it can take floats
        if i >= 5 and not request.finished:
            log.msg("Done")
            request.write("\n</body>")
            request.write("\n</html>")
            # safari will only render when finished
            request.finish()


class Root(Resource):
    isLeaf = False
    def render_GET(self, request):
        return "<html><body>Demo is <a href=\"pe\">here</a></body></html>"




class Site(Site):
    pass



root = Root()
pe = PersistantExample()
site = Site(root)

root.putChild("", root)
root.putChild("index", root)
root.putChild("pe", pe)

# listen
if __name__ == "__main__":
    reactor.listenTCP(8080, site)
    reactor.run()
Run Code Online (Sandbox Code Playgroud)

Zim*_*m3r 1

为了让 Safari 能够渲染 html,在开始渲染接收到的 HTML 之前,至少必须写入 1024 个字节。

您可以在下面看到一个显示工作版本和非工作版本的演示。Firefox 中也会发生类似的情况(因为它需要 1024 字节来确定编码),但您可以在 Firefox 中设置编码以绕过它。不确定 Safari 中是否有办法做到这一点。


+---------------------------------------------------+
| What you send  | How much you need                |
+---------------------------------------------------+
| Nothing        | 1024 bytes                       |
+---------------------------------------------------+
| Meta Charset   | 512 bytes                        |
+---------------------------------------------------+
| Header Charset | 512 bytes (not including header) |
+---------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
import twisted
from twisted.python import log
import sys

log.startLogging(sys.stdout)
from twisted.web.server import Site, NOT_DONE_YET
from twisted.web.resource import Resource
from twisted.internet import reactor

import time


# max 133 
# 133 * 8 = 1064

html_string_working = "<p>" # 3 bytes
html_string_working += "I'm the version that works! I show up right away!" # 49 bytes
html_string_working += "<!---" # 5 bytes
html_string_working += " " * (1024 - (3+49+5+3+4)) # filler
html_string_working += "-->" # 3 bytes
html_string_working += "</p>" # 4 bytes

print len(html_string_working)


html_string_non_working = "<p>" # 3 bytes
html_string_non_working += "I'm the version that does not work! I don't show up right away!" # 63 bytes
html_string_non_working += "</p>" # 4 bytes
html_string_non_working += "<!---" # 5 bytes
html_string_non_working += " " * (1023 - (3+63+5+3+4)) # filler but one byte short (notice 1023 instead of 1024)
html_string_non_working += "-->" # 3 bytes


print len(html_string_non_working)

# charset maybe? Firefox won't start parsing until 1024
# unless it has charset specified see https://bugzilla.mozilla.org/show_bug.cgi?id=647203
# "Your script does not appear to declare the character encoding. When the character
# encoding is not declared, Gecko won't start parsing until it has received 1024
# bytes of HTTP payload."

# charset works but requires 512 bytes
html_string_charset = "<meta charset=utf-8>" # 20 bytes
html_string_charset += "<p>" # 3 bytes
html_string_charset += "I'm the meta charset version. I may work!" # 41 bytes
html_string_charset += "</p>" # 4 bytes
html_string_charset += "<!---" # 5 bytes
html_string_charset += " " * (512 - (20+3+41+5+3+4)) # filler but one byte short (512 bytes; 511 doesn't work)
html_string_charset += "-->" # 3 bytes

# what about in header form
# charset works but requires 512 bytes not including the headers (so same as meta version)
html_string_charset_headers = "<p>" # 3 bytes
html_string_charset_headers += "I'm the header charset version. I may work!" # 43 bytes
html_string_charset_headers += "</p>" # 4 bytes
html_string_charset_headers += "<!---" # 5 bytes
html_string_charset_headers += " " * (512 - (3+43+5+3+4)) # filler but one byte short (512 bytes; 511 doesn't work)
html_string_charset_headers += "-->" # 3 bytes


print len(html_string_charset_headers)


later = "<p> I'm written later. Now it suddenly will work because bytes >= 1024." # 71 bytes

class PersistantExample(Resource):
    '''Gives an example of a persistant request'''
    # does not exist on Safari until stopping browser / ending connection

    isLeaf = True
    def render_GET(self, request):
        log.msg("Ooooh a render request")
        # schedule the reoccuring thing (this could be something else like a deferred result)
        # firefox require the char set see https://bugzilla.mozilla.org/show_bug.cgi?id=647203

        # render working version or not
        try:
            w = int(request.args["w"][0])
        except:
            w = 1

        if w == 1:
            request.write(html_string_working)
        elif w == 2:
            request.write(html_string_non_working)
        elif w == 3:
            request.write(html_string_charset)
        elif w == 4:
            # 12 + 24 = 36 bytes but doesn't count towards 512 total
            request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")
            request.write(html_string_charset_headers)

        reactor.callLater(2, self.run_later, request)

        return NOT_DONE_YET


    def run_later(self, request):
        request.write(later)
        request.finish()





class Root(Resource):
    isLeaf = False
    def render_GET(self, request):
        return """<html><body>

        <p><a href="pe?w=1">Working version here</a></p>
        <p><a href="pe?w=2">Non working version here</a></p>
        <p><a href="pe?w=3">Meta charset version here</a></p>
        <p><a href="pe?w=4">Header charset version here</a></p>
        </body></html>"""



class Site(Site):
    pass



root = Root()
pe = PersistantExample()
site = Site(root)

root.putChild("", root)
root.putChild("index", root)
root.putChild("pe", pe)

# listen
if __name__ == "__main__":
    print "Running"
    reactor.listenTCP(8080, site)
    reactor.run()
Run Code Online (Sandbox Code Playgroud)