Bunny: A lui non importa niente di niente, è un nichilista.
Drugo: Ah, dev’essere faticoso da morire.
Ebbene si, siamo faticosamente arrivati al capitolo finale, oggi si scrive il codice del nostro mini-modulo lighttpd. Uff, che fatica per il Drugo...
...che fatica... |
// init the plugin data INIT_FUNC(mod_helloworld_init) { ... } // destroy the plugin data FREE_FUNC(mod_helloworld_free) { ... } // handle plugin config and check values SETDEFAULTS_FUNC(mod_helloworld_set_defaults) { ... } // handle uri URIHANDLER_FUNC(mod_helloworld_uri_handler) { ... } // this function is called at dlopen() time and inits the callbacks int mod_helloworld_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("helloworld"); p->init = mod_helloworld_init; p->handle_uri_clean = mod_helloworld_uri_handler; p->set_defaults = mod_helloworld_set_defaults; p->cleanup = mod_helloworld_free; p->data = NULL; return 0; }Come si nota si usano delle macro (gentilmente fornite dall'ambiente di sviluppo lighttpd) per creare delle callback con cui inizializzare una struttura plugin che poi lighttpd userà per gestire il nostro modulo ogni qualvolta arrivi una petizione HTTP che ne richieda l'uso. Per chi vuole approfondire l'argomento callback è già stato ampiamente descritto qui e qui (immagino abbiate già letto quei post... o no?).
Allora, che parti del nostro modulo dobbiamo modificare per fare in modo che, usandolo, ci scriva "Hello, world!" nel browser? Visto che il problema è abbastanza semplice anche il codice da scrivere non sarà molto voluminoso e complesso: ci basterà modificare solo la callback mod_helloworld_uri_handler nella seguente maniera:
URIHANDLER_FUNC(mod_helloworld_uri_handler) { plugin_data *p = p_d; UNUSED(srv); // test modo (return se errore) if (con->mode != DIRECT) return HANDLER_GO_ON; // test uri path (return se errore) if (con->uri.path->used == 0) return HANDLER_GO_ON; mod_helloworld_patch_connection(srv, con, p); // test handler (return se errore) if (con->uri.path->ptr && strstr(con->uri.path->ptr, "helloworld")) { // scrive buffer buffer *b = chunkqueue_get_append_buffer(con->write_queue); BUFFER_APPEND_STRING_CONST(b, "<big>Hello, world!</big>"); // send header response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); con->http_status = 200; con->file_finished = 1; // handling finito return HANDLER_FINISHED; } else return HANDLER_GO_ON; }Ok, come vedete è ampiamente commentato e quindi è auto-esplicativo, per cui non mi dilungherò sulle singole istruzioni e/o gruppi di istruzioni (leggete i commenti! sono li per quello!), ma aggiungerò, solo, qualche dettaglio strutturale.
Alcune parti sono rimaste identiche alla callback originale (ma ho aggiunto dei commenti), e sono tipiche della struttura del codice di lighttpd: per non complicare troppo l'argomento non mi dilungherò su queste parti. Comunque fidatevi perché lighttpd è scritto e funziona come si deve.
La parte veramente nuova che ho scritto è quella che inizia col commento "test handler (return se errore)", dove si testa se la URI passata al browser contiene il nome del modulo e, in quel caso, esegue quello che vogliamo: copia in un buffer la scritta "Hello, world!" e la invia come risposta alla petizione. Quindi se noi scriviamo nella barra degli indirizzi di Firefox, Chrome, Opera (o qualsiasi altro browser meno IE, per favore...)
http://127.0.0.1/helloworldavremo come risposta nel browser:
Hello, world!Ho scritto 127.0.0.1 (e si poteva scrivere anche localhost) perché, ovviamente, il primo test lo faremo in locale. Se poi avete voglia di aprire la vostra macchina al mondo esterno e usarla come un vero Web Server (in una rete locale o nel WWW) potrete ripetere il test usando il vostro indirizzo IP pubblico e otterrete lo stesso risultato. Il modulo funziona!
Il codice appena mostrato l'ho scritto e provato con lighttpd 1.4.33. Se usate una versione più recente (dalla 1.4.36 in avanti) scoprirete che qualcosa è cambiato a livello di gestione dei buffer, quindi ad esempio le linee:
if (con->uri.path->used == 0) ... buffer *buf = chunkqueue_get_append_buffer(con->write_queue);devono diventare:
if (buffer_is_empty(con->uri.path)) ... buffer *buf = buffer_init();ma questi sono dettagli. In futuro, come promesso, vi proporrò qualche modulo più sofisticato, con modifiche anche alle altre callback del modulo, ma questo per il momento può bastare, non gettiamo troppa carne al fuoco, se no ci stanchiamo come il Drugo...
Ciao e al prossimo post!
Nessun commento:
Posta un commento