[Python] mod_python ed il giusto handler

Andrea Giammarchi andrea a 3site.it
Mer 16 Ago 2006 18:30:23 CEST


Ma porca trota (scusa, intanto grazie) .. è tutto il pomeriggio che 
sbatto la testa con questo mod_python ed ora viene fuori questo 
framework favoloso ?

vabbeh ... proverò a continuare per la mia strada (poi un giorno 
spiegherò anche il perchè o dove vorrei arrivare) con mod_python

Le conclusioni sono state le seguenti:

 - publisher, come handler (credo lo stesso di django o simile), non è 
dei più performanti
 - psp pare sia tra i più performanti dopo la configurazione a singolo 
file (anche se gestisce un embed stile Ruby on Rails o PHP, quindi non 
so quanto sia veramente performante ... sicuramente più degli altri 
appena citati)

In generale ho notato che la semplicità del php con le cose più banali 
($_GET, $_POST, $_FILE) non esiste con nessun handler (ma le super 
globali, o almeno la loro netta distinzione, le trovo estremamente utili 
...).

Zope da quanto ho visto può andare anche sotto Apache e mod_python, Zope 
si prende solo qualche variabile del server per partire e niente più.
Zope l'ho imitato per la scrematura di variabili ad eccezione del path 
che l'ho aggiunto.

Mi sono anche scervellato per riuscire a fare una classe per delle super 
globali PHP-STYLE molto fake, questo è quanto ne è venuto fuori:

### Andrea Giammarchi
# PHPRequestVars alpha 1

import mod_python

class PHPRequestVars:

    def getPHPFakeEnviroment(self):
        return {'SERVER':self.__SERVER, 'GET':self.__GET, 
'POST':self.__POST, 'FILES':self.__FILES}
   
    def __init__(self, HTTPRequest):
       
        self.__SERVER = {}
        self.__GET = {}
        self.__POST = {}
        self.__FILES = {}
       
        HTTPRequest.add_common_vars()
        for k,v in HTTPRequest.subprocess_env.iteritems():
            if k.startswith('HTTP_') or k.startswith('PATH_') or 
k.startswith('SERVER_') or k.startswith('REQUEST_') or k in 
['CONNECTION_TYPE','REMOTE_ADDR','QUERY_STRING','CONTENT_LENGTH','CONTENT_TYPE','SCRIPT_FILENAME']:
                self.__SERVER[k] = v
        if HTTPRequest.headers_in.has_key('authorization'):
            self.__SERVER['HTTP_AUTHORIZATION'] = 
HTTPRequest.headers_in['authorization']
        self.__SERVER['GATEWAY_INTERFACE'] = 'Python/mod_python.publisher'
        self.__SERVER['SCRIPT_NAME'] = ''
        if self.__SERVER.has_key('REQUEST_URI'):
            self.__SERVER['PATH_TRANSLATED'] = 
self.__SERVER['PATH_INFO'] = self.__SERVER['REQUEST_URI'].split('?')[0]
        if self.__SERVER.has_key('HTTP_CONNECTION'):
            self.__SERVER['CONNECTION_TYPE'] = 
self.__SERVER['HTTP_CONNECTION']
        if self.__SERVER.has_key('QUERY_STRING') and 
len(self.__SERVER['QUERY_STRING']) > 0:
            self.__initGet(self.__SERVER['QUERY_STRING'].split('&'))
        if self.__SERVER.has_key('REQUEST_METHOD') and 
self.__SERVER['REQUEST_METHOD'] == 'POST':
            self.__initPostAndFiles(HTTPRequest)
   
    def __initGet(self, queryString):
        j = len(queryString)
        tmp = []
        for i in range(0, j):
            tmp = queryString[i].split('=')
            if len(tmp) == 2:
                self.__GET[tmp[0]] = tmp[1]
            else:
                self.__GET[tmp[0]] = ''

    def __initPostAndFiles(self, HTTPRequest):
        tmplist = mod_python.util.FieldStorage(HTTPRequest).list
        j = len(tmplist)
        for i in range(0, j):
            if tmplist[i].file.__class__.__name__ != 
'_TemporaryFileWrapper':
                if not self.__GET.has_key(tmplist[i].name):
                    self.__POST[tmplist[i].name] = tmplist[i].value
                elif self.__GET[tmplist[i].name] != tmplist[i].value:
                    self.__POST[tmplist[i].name] = tmplist[i].value
                   
            else:
                cname = tmplist[i].value
                self.__FILES[tmplist[i].name] = {
                    'name':tmplist[i].filename,
                    'type':tmplist[i].type,
                    'tmp_name':tmplist[i].file.__dict__['name'],
                    'size':len(cname),
                    'data':cname,
                    'error':0
                }


e questa è la pagina index.psp che sto usando per fare i tests:

<%
from PHPRequestVars import *

def index(HTTPRequest):
    buffer = []
    phpFakeEnv = PHPRequestVars(HTTPRequest).getPHPFakeEnviroment()
   
    _SERVER = phpFakeEnv['SERVER']
    _GET = phpFakeEnv['GET']
    _POST = phpFakeEnv['POST']
    _FILES = phpFakeEnv['FILES']
   
    buffer.append('<pre>')
    for k in _POST:
        buffer.append('_POST:    %s        %s<br />' % (k, _POST[k]))
    buffer.append('</pre>')
   
    buffer.append('<pre>')
    for k in _GET:
        buffer.append('_GET:    %s        %s<br />' % (k, _GET[k]))
    buffer.append('</pre>')
   
    buffer.append('<pre>')
    for k in _FILES:
        buffer.append('_FILES:    %s        %s<br />' % (k, 
_FILES[k]['name']))
    buffer.append('</pre>')
   
    buffer.append('<hr /><pre>')
    for k in _SERVER:
        buffer.append('_SERVER:    %s        %s<br />' % (k, _SERVER[k]))
    buffer.append('</pre>')

    HTTPRequest.content_type = "text/html"
    HTTPRequest.send_http_header()
    HTTPRequest.write("".join(buffer))

index(req)
%>

Ora, funziona tutto alla perfezione (almeno dai tests che ho fatto io) 
ma ho un enorme dubbio sulla variabile _FILE, in particolare in questo 
pezzo:

                cname = tmplist[i].value
                self.__FILES[tmplist[i].name] = {
                    'name':tmplist[i].filename,
                    'type':tmplist[i].type,
                    'tmp_name':tmplist[i].file.__dict__['name'],
                    'size':len(cname),
                    'data':cname,
                    'error':0
                }

il dubbio nasce dal fatto che mod_python si comporta in modo diverso da 
mod_php e da quanto ho letto cname = tmplist[i].value può mandare in 
tilt il web-server perchè carica in memoria tutto il file come stringa 
binaria non appena richiamato.
Non ho trovato il modo di prendere la size del file inviato se non 
sfruttando la len del binario ed a quel punto ho optato per l'aggiunta 
di un campo data contenente tale stringa.

Ovviamente se i files sono molto grandi il server va in crisi .... avete 
consigli sul come gestire il tutto o chiudere il file inviato al fine di 
poter leggere la size e non quella attesa, ovvero 0L ??? (os.stat(..)[6] 
già provato)

Grazie ancora, se sono uscito dal tema apro un'altra email ?

Saluti,
    Andrea Giammarchi

P.S. ogni altro consiglio sul codice postato è ben accetto



Carlo C8E Miron ha scritto:
>> - ce ne sono altri ??? ... qual'è il più usato ?
>
> Django, <http://djangoproject.com/> 


Maggiori informazioni sulla lista Python