Frage zum SimpleHTTP Server

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
ds2k5
User
Beiträge: 3
Registriert: Samstag 17. Dezember 2016, 15:35

Hallo,
ich habe unter Python 3.4.2 einen Beispiel Code ausprobiert für einen HTTP Server.

Wenn ich dieses dann z.B: mit nmap scanne sieht man: SimpleHTTPServer 0.6 (Python 3.4.2)
Wie kann man die "Info" ausschalten bzw. ändern ?

Danke

Code:

Code: Alles auswählen

#!/usr/bin/python3
#
import http.server
import socketserver

PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()
Zuletzt geändert von Anonymous am Samstag 17. Dezember 2016, 16:26, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Das liegt wohl an den Headern, die der Server sendet: https://hg.python.org/cpython/file/1756 ... er.py#l478

Das kann man auch relativ einfach im Browser nachvollziehen: Bild (oder via `curl -I`)

`server_version` zu überschreiben sollte hier ausreichen. (`server_version` ist natürlich auch in der Dokumentation zu finden)
the more they change the more they stay the same
ds2k5
User
Beiträge: 3
Registriert: Samstag 17. Dezember 2016, 15:35

Vielen Dank

bekomm es zwar im Moment nicht zum laufen...
aber ich hoffe ich finde meine Fehler
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

ds2k5 hat geschrieben:ich habe unter Python 3.4.2 einen Beispiel Code ausprobiert für einen HTTP Server.

Wenn ich dieses dann z.B: mit nmap scanne sieht man: SimpleHTTPServer 0.6 (Python 3.4.2)
Wie kann man die "Info" ausschalten bzw. ändern ?
Dies kannst Du ändern, indem Du einen eigenen RequestHandler definierst und verwendest. 'server_version' ist ein Klassen-Attribut das bei Aufruf von 'version_string()' mit der System-Version konkateniert wird. Überladen dieser Methode und setzen des Klassen-Attributes erlaubt Dir dann, jede beliebige Info, oder auch gar keine, auszugeben:

Code: Alles auswählen

import http.server
import socketserver

class MyRequestHandler(http.server.SimpleHTTPRequestHandler):

    def version_string(self):
        """Return the server software version string."""
        return self.server_version
    
PORT = 8000
Handler = MyRequestHandler
Handler.server_version = 'MyServer 0.1'
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()
Wobei mir die Lösung mit dem Klassen-Attribut nicht sonderlich gefällt, aber in der Standard-Library ist es so implementiert. Bei einem eigenen RequestHandler würde ich es wohl als Instance-Attribut anlegen.
BlackJack

@kbr: Die Idee ist wohl eher den Wert auch in der abgeleiteten Klasse als Klassenattribut zu definieren und nicht von ”aussen” auf der Klasse zu setzen.

Code: Alles auswählen

class MyRequestHandler(http.server.SimpleHTTPRequestHandler):

    server_version = 'My Superserver 42.23'

    def version_string(self):
        """Return the server software version string."""
        return self.server_version
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: für jeden Request wird eine Handler-Instanz erzeugt, aber Du willst ja nicht für jede Instanz eine andere Server-Version. Daher ist hier ein Klassenattribut genau das richtige, das man ja, wie BlackJack schon geschrieben hat, bei der Klasse definiert und nicht außerhalb setzt. Warum nennst Du MyRequestHandler in Handler um? Das könnte suggerieren, dass man server_version individuell setzen könnte, was so nicht geht.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: oder so. Aber wenn das Klassen-Attribut in der abgeleiteten Klasse angelegt wird, muss dies auch wieder von außen gesetzt werden, wenn die Ausgabe der Information geändert werden soll, bzw unterdrückt werden soll – sofern Du dafür nicht auch eine eigene Klasse anlegst.

@Sirius3: Ich habe einfach das Originalbeispiel verwendet. Die Umbenennung ist auch dort nicht erforderlich und vermeidet nur eine lange nachfolgende Zeile.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: wie schon gesagt, die Version ist nichts, was man pro Request setzen will. Daher ist der übliche Weg, die Handler-Klasse abzuleiten und Klassenvariablen zu setzen und/oder Methoden zu überschreiben.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: Das hat mit pro Request nichts zu tun, sondern mit pro Applikation. Wenn die Server-Version als Klassen-Attribut angelegt ist, dann muss diese eben von außen geändert werden, wenn eine andere Information geliefert werden oder die bestehende unterdrückt werden soll. Statt dessen dafür ein Instanz-Attribut zu verwenden bietet allerdings keinen Vorteil, wie ich nach absenden meines Postings gesehen habe.
BlackJack

@kbr: Ich verstehe nicht worauf Du mit Deiner Argumentation hinaus willst. Wenn ich eine andere Anwendung schreibe, dann hat die ja auch einen anderen Handler, also eine eigene Klasse der ich auch ein eigenes `server_version`-Attribut spendieren kann. Das was Du da machst ist eine globale Variable verändern, bzw. aus etwas das eigentlich eine Konstante sein sollte, eine Variable, und dann auch noch eine globale, zu machen.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: Ob Du nun eine neue Klasse schreibst oder von einer bestehenden ein Klassen-Attribut änderst, macht keinen Unterschied, solange Instanzen der geänderten Klasse nicht auch noch woanders verwendet werden. Und dies ist ja hier nicht der Fall. Aber im Prinzip ist das schon richtig: im zweiten Fall lauern potentiell Seiteneffekte.

Was ich für den OP gerne hätte, wäre so etwas:

Code: Alles auswählen

handler = get_signature_handler(SimpleHTTPRequestHandler, 'MySuperServer')
Daher meine ursprüngliche Idee einer Instanz-Variablen. Aber nicht jede Idee ist eine gute Idee und wenn ich in den Sourcecode schaue, wäre dies, von der Sinnhaftigkeit einmal abgesehen, auch gar nicht so einfach umzusetzen.

Am saubersten ist in der Tat eine separate Klasse mit eigenem Klassen-Attribut. Für jede Anwendung aber alleine wegen der Server-Information einen eigenen Handler schreiben zu müssen, ist auch nicht so toll. Zum Glück geht das auch 'einfacher':

Code: Alles auswählen

def get_signature_handler(handler, server_version='', sys_version=''):
    d = {'server_version': server_version, 'sys_version': sys_version}
    return type('SignatureHandler', (handler,), d)
Das ist natürlich auch nur wieder eine weitere Idee und muss nicht der Weisheit letzter Schluß sein ... :)
BlackJack

@kbr: Ich verstehe es immer noch nicht so wirklich. Natürlich für jede Anwendung eine eigene Handler-Klasse, denn das muss man doch *sowieso* machen. Nicht alleine wegen der Serverinformation, sondern weil jede Anwendung ja auch etwas anderes *macht*. Sonst wär's ja keine andere Anwendung sondern die gleiche, und bei gleicher Anwendung ist die gleiche Serverinformation ja auch normal.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: Mag ja sein. Die Frage des OP war, wie er die Meldung modifizieren kann. Das wird er nun wohl können. Welches Vorgehen er dafür in seiner Situation als sinnvoll erachtet bleibt ihm überlassen – so wie Dir auch.
Antworten