Search code examples
pythonfontstwistedtwisted.web

Twisted server returning text with unexpected fonts


My current twisted server code. It is a simple experiment to take url encoded requests and convert them into a JSON like string to then return.

from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor
import urllib.parse

class FormPage(Resource):
    isLeaf = True
    def render_GET(self, request):
        print(request.uri)
        x = (request.uri).decode('ascii')
        x = x[1:]
        x = todi(x)
        return x.encode('ascii')
def todi(st):
    if len(st) == 0:
        return '{}'
    if st[len(st)-1] == '/':
        st = st[:-1]
    if len(st) == 0:
        return '()'
    if st[0] == '?':
        st = st[1:]
    st = urllib.parse.parse_qsl(st)
    return str(dict(st))



factory = Site(FormPage())
reactor.listenTCP(80, factory)
reactor.run()

I've paid attention to the font my browser displays when I am receiving simple text. For example this site: http://icanhazip.com/ when you visit, the font looks like consola font (default font for MS notepad). However, when I visit my site, my browser displays a font that looks like Times New Roman.

I have done some debugging since, such as forcing the site to return a simple string of characters, but nothing can stop twisted from giving me ugly looking fonts.

Here, have an example.

Also note that I did the thing in Chrome where you right click and use the "View page source" button. Trust me, both my examples are simply raw text according to that.


Solution

  • Looking at the headers returned by your Twisted server and comparing them to those returned by the other web site, the latter specifies Content-Type: text/plain; charset=UTF-8, whereas the Twisted server does not specify the Content-Type at all.

    Your browser (and I've found it to be the same with Firefox) uses a different font when the content type is specified as text/plain vs. an unspecified content type.

    In Twisted you can set the Content-Type header with request.setHeader() like this:

    def render_GET(self, request):
        print(request.uri)
        x = (request.uri).decode('ascii')
        x = x[1:]
        x = todi(x)
        request.setHeader('Content-Type', 'text/plain; charset=UTF-8')
        return x.encode('UTF-8')
    

    As this sets the Content-Type it might as well specify the charset too. UTF-8 is (probably) preferred, and the response text is similarly encoded.