'python and BaseHTTPRequestHandler : add an empty favicon in the header of the generated page

On python 3.8, I created a minimalist python server for my students with BaseHTTPRequestHandler and HTTPServer from the module http.server

When I go to the url on the server, I see in the browser debug tool two http request :

  • one for the page
  • one for the favicon (the current head html page does not contains a link tag for a favicon, the current head is empty)

enter image description here

I want to prevent the second request (for favicon). My question is : with the classes "BaseHTTPRequestHandler" and "HTTPServer" is it possible to custom the header of the generated page ? I am looking for a way to add an empty favicon like this : <link rel="icon" href="data:;base64,="> (https://stackoverflow.com/a/13416784/2137454)



Solution 1:[1]

from http.server import SimpleHTTPRequestHandler


class CustomHttpRequestHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/favicon.ico':
            self.send_response(200)
            self.send_header('Content-Type', 'image/x-icon')
            self.send_header('Content-Length', 0)
            self.end_headers()
            return

        return super().do_GET()

This will suppress the console error as Chrome thinks it has received a favicon -- even though it is a 0-byte response with a correct content type and response code.

Solution 2:[2]

It is clearly possible. After all, you are in complete control of what your server sends to the client. However, I think you should not do this. Just serve that annoying little file favicon.ico. It is the easiest way:

import socketserver
from http.server import SimpleHTTPRequestHandler


class CustomHttpRequestHandler(SimpleHTTPRequestHandler):

    def do_GET(self):
        if self.path == '/':
            # here do whatever your custom server would normally do
            self.path = 'static/index.html'

        if self.path == '/favicon.ico':
            self.path = 'static/favicon.ico'

        return SimpleHTTPRequestHandler.do_GET(self)


if __name__ == '__main__':
    PORT = 8001
    my_server = socketserver.TCPServer(("", PORT), CustomHttpRequestHandler)
    my_server.serve_forever()

To make this work, all you need to do is to place a png file in folder static and name it favicon.ico.

Of course, you could also modify the html content you are sending. As there is no code in your question, I hacked a little mock together:

import socketserver
from http.server import SimpleHTTPRequestHandler
import io

favicon = '<link rel="icon" href="data:;base64,=">\n'


class CustomHttpRequestHandler(SimpleHTTPRequestHandler):

    def do_GET(self):
        if self.path == '/':
            self.path = 'index.html'

        f = self.send_head()  # f is the file to send or None

        # following code will break easily. don't do this...
        content = ""
        for line in f:
            line = line.decode("utf8")
            # 'parsing' html like this is really a bad idea. don't do it...
            if "</head>" in line:
                content += favicon
            content += line

        f2 = io.BytesIO(content.encode("utf-8"))
        self.copyfile(f2, self.wfile)


if __name__ == '__main__':
    PORT = 8001
    my_server = socketserver.TCPServer(("", PORT), CustomHttpRequestHandler)
    my_server.serve_forever()

Here I am assuming, you are serving a static file from the current directory. Before sending it to the client the <link rel="icon"> tag is appended right before the closing <head> tag. This will break easily, of course. But if you are indeed generating the html instead of serving a static file, placement of the line content += favicon in your code might be simple and save.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MrValdez
Solution 2 Lydia van Dyke