1

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)

spacecodeur
  • 2,206
  • 7
  • 35
  • 71

2 Answers2

3
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.

MrValdez
  • 8,515
  • 10
  • 56
  • 79
eat-sleep-code
  • 4,753
  • 13
  • 52
  • 98
  • Not an python export, but the `return super().do_GET()` should be `return super().do_GET(self)`? Thanks. – ollydbg23 Aug 24 '22 at 08:42
1

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.

Lydia van Dyke
  • 2,466
  • 3
  • 13
  • 25