CGI und Binärdaten

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 30. November 2004, 18:20

Hi,
ich habe folgendes vor: ich habe ein Script, dass Dateien herunterlädt und selbst wieder ausgibt. Am besten ich schicke mal den Code:

Code: Alles auswählen

import cgi, urllib, sys
import cgitb

def initpage(mime="text/plain"):
    print "Content-Type: %s" % mime
    print

def getfile(url):
    # remote - file like object
    try:
        remote = urllib.urlopen(url)
        # content type
        mime = remote.headers.gettype()
        return (remote, mime)
    except IOError:
        raise IOError('No such file or directory')

def main():
    cgitb.enable()
    form = cgi.FieldStorage()
    
    # get url field
    try:
        url = form['url'].value
    except KeyError:
        url = None
    
    # get extension field
    try:
        ext = form['ext'].value
    except KeyError:
        ext = None
    
    if not url or not ext:
        initpage('text/html')
        print '<html><head><title>Too less args given, Sai</title></head><body>You need to specify URL and EXT</body></html>'
        sys.exit(100)
    
    # okay, let's start work!
    try:
        # we try to get that URL
        remotefile = getfile(url)
        # well done, now initialise the page with the proper Content Type (determined by the content type of the ur)
        initpage(mime=remotefile[1])
        #print 'File found'
        
        print remotefile[0].read()
    except IOError:
        initpage('text/html')
        print '<html><head><title>No such file, Sai</title></head><body>No such file: %s</body></html>' % url

if __name__ == '__main__':
    main()
das Ding ist ein CGI und sollte so aufgerufen werden:
relocate.py?url=http://www.google.de/intl/de_de/images/logo.gif&ext=abc
Ext=abc, damit da einfach etwas steht, vielleicht kommt später noch etwas dazu, dass es auch wirklich nutzt. Nun, wenn ich ihm HTML Dateien zu futtern gebe gibt es kein Problem, aber wenn ich Binärdateien wie eben das Google Logo nehme läuft es zwar durch, aber der Browser zeigt einen Fehler. Ich nehme an, dass ich bei read() noch ein encode() machen muss, aber was für einen Codec soll ich nutzen?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 30. November 2004, 18:36

Interessantes Skript, frag mich wohin die Reise gehen soll :)

Ich würd erst mal ein bischen mit print Debuggen... Naja, vielleicht erst mal nur den "mime"-Typ ausgeben...

Wie sieht der aus, wenn du ein Bild umleiten willst? Wird der richtig per remote.headers.gettype() erkannt?
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 30. November 2004, 19:04

jens hat geschrieben:Interessantes Skript, frag mich wohin die Reise gehen soll :)
Die Reiseroute soll ein paar Stolperfallen zwischen Webserver und Rechner umgehen..
jens hat geschrieben:Ich würd erst mal ein bischen mit print Debuggen... Naja, vielleicht erst mal nur den "mime"-Typ ausgeben...
Hihi, habe ich schon oft gemacht.
jens hat geschrieben:Wie sieht der aus, wenn du ein Bild umleiten willst? Wird der richtig per remote.headers.gettype() erkannt?
Jep, absolut richtig, image/gif und bei PNGs image/png. Ich habe jetzt das Logo einmal vom direkt vom Browser und einmal durch das Script laufen lassen. Ich habe beide Dateien gespeichert und festgestellt, dass da ein Unterschied ist: die eine hat eine Zeile 82, die andere nicht. Nachdem ich diese gelöscht habe, gab es laut Total Commander 0 Unterschiede (aber scheinbar doch nicht identisch) und die Datei wollte sich immernoch nicht anzeigen lassen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Dienstag 30. November 2004, 20:07

Hi. Ganz einfach :wink: :

Code: Alles auswählen

        print remotefile[0].read()
wird zu

Code: Alles auswählen

        import sys
        sys.stdout.write(remotefile[0].read())
Liegt daran, dass print immer noch ein Newline an die Ausgabe anhängt :)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 1. Dezember 2004, 12:50

Aber sowas sollte doch auch gehen (tut es aber nicht):

Code: Alles auswählen

print remotefile[0].read(),
Und nein, das will irgendwie nicht.

Nachtrag: laut UltraEdit sind die Dateien nicht gleich, aber ähnlich. Kann mir jemand sagen, warum das so ist? In meiner version des GIF Bildes fehlen einfach einige "Zeilen" leer, statt dem Binärzeug einfach gar nichts. Hilfe!
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 1. Dezember 2004, 13:15

Okay, ich habe es doch jetzt geschafft, dank diesem Rezept. Ich habe vergessen, dass das CGI wärend ich daran baue auf einem Windows Abyss Server läuft (Apache habe ich zwar auch aber das wäre einiges an aufwand den umzukonfigurieren). Unter windows muss man das stdout auf Binär stellen! Und das schimpft sich OS!

Der korrigierte Code ist:

Code: Alles auswählen

import cgi, urllib, sys
import cgitb

def initpage(mime="text/plain"):
    print "Content-Type: %s" % mime
    print

def getfile(url):
    # remote - file like object
    try:
        remote = urllib.urlopen(url)
        # content type
        mime = remote.headers.gettype()
        return (remote, mime)
    except IOError:
        raise IOError('No such file or directory')

def main():
    cgitb.enable()
    form = cgi.FieldStorage()
    
    # get url field
    try:
        url = form['url'].value
    except KeyError:
        url = None
    
    # get extension field
    try:
        ext = form['ext'].value
    except KeyError:
        ext = None
    
    if not url or not ext:
        initpage('text/html')
        print '<html><head><title>Too less args given, Sai</title></head><body>You need to specify URL and EXT</body></html>'
        sys.exit(100)
    
    # okay, let's start work!
    try:
        # we try to get that URL
        remotefile = getfile(url)
        # well done, now initialise the page with the proper Content Type (determined by the content type of the ur)
        initpage(mime=remotefile[1])
        #initpage()
        #print 'File found'
        
        #print remotefile[0].read(),
        if sys.platform == "win32":
            import os, msvcrt
            msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
        sys.stdout.write(remotefile[0].read())
        #print dir(remotefile[0].read())
        #print remotefile[0].headers
    except IOError:
        initpage('text/html')
        print '<html><head><title>No such file, Sai</title></head><body>No such file: %s</body></html>' % url

if __name__ == '__main__':
    main()
Nun, das ist schonmal sehr gut. Jetzt geht es daran, EXT benutzbar zu machen, denn wenn ich es so aufrufe:
relocate.py?url=http://127.0.0.1/cgi-bin/relocate.py?ur ... ip&ext=abc
Dann bekomme ich eine Datei namens relocate.py mit Zip inhalt zugespielt (der Inhalt ist in Ordnung). Wie kann ich jetzt aber statt relocate.py ein wxUniGet.abc bekommen? Hibt es header die ich schicken kann die dem Browser sagen: benenne das Ding nach dem Download um, oder, speichere es (per default) als wxUniGet.abc?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Mittwoch 1. Dezember 2004, 16:38

Hi

Ja gibt es.
Du suchst glaubs:
Content-Disposition: attachment; filename="wxUniGet.abc"

einfach nach Content-Type einfügen


Gruss
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 1. Dezember 2004, 17:09

rayo hat geschrieben:Ja gibt es.
Du suchst glaubs:
Content-Disposition: attachment; filename="wxUniGet.abc"

einfach nach Content-Type einfügen
Genau das was ich gesucht habe! Danke, es funktioniert genau so wie ich wollte! Was würde ich nur ohne dieses Forum machen?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Antworten