O
Tufão é inspirado no projeto Node.js. Assim, o núcleo de ambos é bem similar. Para suprir a programação orientada a eventos do JavaScript usada no Node.js, o mecanismo Signals & Slots do Qt é utilizado.
Com exceção dos DEFINEs (por motivos óbvios), todos os símbolos declarados nos cabeçalhos da biblioteca pertencem ao namespace Tufao e todos os arquivos de cabeçalho encontram-se dentro da pasta Tufao.
O principal trabalho de uma biblioteca que abstrai o protocolo HTTP é interpretar e formatar mensagens. No Tufão, esse trabalho é feito pelas classes HttpServerRequest e HttpServerResponse, respectivamente. Para facilitar ainda mais o processo, existem as classes HttpServer e HttpsServer, que abstraem o processo de tratar conexões TCP e SSL. Em uma aplicação Hello World, você chamaria a função QObject::connect para realizar a parte principal do trabalho:
QObject::connect(&server,
SIGNAL(requestReady(Tufao::HttpServerRequest*,Tufao::HttpServerResponse*)),
&handler,
SLOT(handleRequest(Tufao::HttpServerRequest*,Tufao::HttpServerResponse*)));
E implementaria o handler com o seguinte SLOT:
void Handler::handleRequest(Tufao::HttpServerRequest *request,
Tufao::HttpServerResponse *response)
{
response->writeHead(Tufao::HttpServerResponse::OK);
response->headers().insert("Content-Type", "text/plain");
response->end("Hello World\n");
}
Os principais métodos da classe HttpServerResponse são writeHead, headers, write e end. Com eles, é possível formar e enviar a mensagem de resposta para a requisição. Como visto anteriormente, a mensagem possui partes bem definidas e ordenadas, não sendo possível enviar o corpo de mensagem antes dos cabeçalhos, por exemplo. Assim, você deve chamar os métodos em ordem.
A primeira informação que você deve fornecer é a linha de status, que informa um código indicando a validade da requisição, através do método writeHead. Após isso você pode enviar quantos pedaços da mensagem quiser, através do método write, e finalizar a resposta com o método end.
Duas características importantes a ter em mente é que qualquer cabeçalho a ser definido, deve sê-lo antes de qualquer chamada a write, e que a versão 1.0 do protocolo HTTP não suporta receber a mensagem em pedaços. Assim, nesses casos, o Tufão irá usar um buffer interno para guardar todos os pedaços na memória antes de enviá-los. Dependendo de sua aplicação, pode ser interessante bloquear certas páginas para clientes que usam o HTTP/1.0, ou mesmo enviar uma entidade alternativa.
No Tufão 1.0 (que pretendo lançar após o Qt5), pretendo permitir o uso lambdas em vários pontos onde fazem sentido, mas, no momento, isso não é possível de modo natural. Essa funcionalidade permitirá criar aplicações usando ainda menos linhas de código e, ao mesmo tempo, torná-las mais legíveis.
Um dos problemas em tratar requisições HTTP da forma demonstrada no código anterior é a possibilidade de criar "classes Megazord". Caso você não tenha imaginado como isso pode ocorrer, o seguinte pedaço de código pode lhe dar uma pista:
if (request->url() == "/user") {
// ...
} else if (request->url() == "/community") {
// ...
} else if (request->url() == "/page") {
// ...
} else if (request->url() == "/about") {
// ...
Para evitar o tratamento de várias páginas diferentes na mesma função, você pode usar um roteador de requisições, que encaminha as requisições para os handlers corretos. O roteador disponível no Tufão permite que você utilize expressões regulares para filtrar a URL das requisições e filhos da classe AbstractHttpServerRequestHandler como handlers.
Os handlers implementam o método handleRequest, que retorna um valor booleano indicando se a requisição foi ou não tratada. Caso a requisição não seja tratada, ela é encaminhada para o próximo handler cujo filtro satisfaz a requisição. Essa arquitetura é bem flexível e útil. Dois usos interessantes são criar handlers do tipo fallback (para navegadores antigos, por exemplo) e criar handlers que definem cabeçalhos que devem estar presentes em todas as respostas (o cabeçalho Date, por exemplo).
Duas particularidades presentes no roteamento de requisições do Tufão é que é possível aninhar roteadores, pois a classe que faz o roteamento também é filha de AbstractHttpServerRequestHandler, e é possível carregar plugins para usar como handlers, através da classe HttpPluginServer. Para ter uma ideia rápida de como utilizar esses recursos do Tufão, crie, no QtCreator, uma aplicação a partir do modelo "application":
E leia a documentação caso queira detalhes de como os mesmos se comportam. Existem várias outras facilidades documentadas disponíveis no Tufão, leiam a documentação.