# Construindo um Web server com Login & Logout

Na última seção vimos como construir um web server simples. Passamos por fundamentos e anatomia de uma mensagem HTTP.

Como próximo passo, vamos construir um web server completo, com funcionalidade de Login e também Logout. Desta forma poderemos compreender mais algumas partes fundamentais da Web.&#x20;

> Para os mais ansiosos, segue [este link](https://gist.github.com/leandronsp/3a81e488b792235b2be73f8def2f51e6) para o Gist com o código completo de um web server com Login & Logout em bash. Já para quem quer entender como funciona esse tipo de sistema na web, continue acompanhando o guia até ao fim.

### Provendo uma resposta dinâmica

Até agora, temos visto uma representação estática de resposta do server:

```bash
$ echo -e 'HTTP/1.1 200\r\n\r\n\r\n<h1>PONG</h1>' | nc -lvN 8080

Listening on 0.0.0.0 8080
```

Não importando qual request será enviado, o response será sempre o mesmo:

```bash
$ curl http://localhost:8080/
<h1>PONG</h1>

$ curl http://localhost:8080/users
<h1>PONG</h1>

$ curl -X POST http://localhost:8080/login -d name=Leandro
<h1>PONG</h1>
```

Entretanto, precisamos de uma resposta dinâmica, onde, dependendo do caminho da URL no request, o server poderá devolver uma mensagem diferente. Mas como fazemos isto?&#x20;

Para chegarmos a uma solução, vamos entender o mecanismo de redirecionamentos de streams com o comando `netcat`.

#### O comando netcat fica bloqueado à espera de mensagens no socket

Assim que o comando `nc` é iniciado, um socket é criado na porta escolhida e portanto fica à espera de mensagens em novas conexões criadas no socket.

#### O input (STDIN) do comando  é utilizado posteriormente como resposta HTTP no socket

Qualquer input passado ao comando `nc`, seja via interface STDIN ou redirecionado com UNIX pipe, é enviado posteriormente como resposta.

#### Qualquer request HTTP é enviado para o output (STDOUT) do comando

Quando uma mensagem chega em conexão no socket, esta é enviada para o STDOUT, ou pode ser redirecionada com UNIX pipe.&#x20;

```bash
## 1. Server fica bloqueado à espera de requests HTTP no socket
## 2. Quando um request HTTP chega, este é enviado para o STDOUT
## 3. O server agora fica bloqueado à espera de mensagem no STDIN, para ser 
##    enviada como HTTP response no socket
## 4. O response HTTP é enviado e a conexão com o client é encerrada
$ nc -lvN 8080
Listening on 0.0.0.0 8080
```

Em resumo, STDIN do `nc` é enviado como HTTP response. E requests HTTP são enviados para o STDOUT.&#x20;

Sabendo disto, podemos utilizar UNIX pipes para criar uma pipeline de request-response dinâmica, assim deixamos nosso server um pouco mais sofisticado pronto a receber funcionalidades mais avançadas.&#x20;

```bash
## Server
$ echo -e "HTTP/1.1 200\r\n\r\n\r\n<h1>PONG</h1>" > response.html
$ cat response.html | nc -lvN 8080
Listening on 0.0.0.0 8080
```

Agora, ao fazer o request com `curl`:

```bash
$ curl http://localhost:8080/
<h1>PONG</h1>
```

O problema da resposta estática ainda não foi resolvido. E se, ao invés de fazermos o `cat` a partir de um arquivo estático, optarmos por fazer o `cat` a partir de uma estrutura dinâmica?

Tal estrutura pode funcionar como uma fila síncrona, onde o conteúdo da estrutura só é lido quando algum outro processo tiver escrito.&#x20;

Sim, estamos falando de named pipes.

<pre class="language-bash"><code class="lang-bash"><strong>## Server
</strong><strong>$ mkfifo response
</strong>$ cat response | nc -lvN 8080
Listening on 0.0.0.0 8080

## Client
$ curl http://localhost:8080/

## Outra sessão, escrever no named pipe (response)
$ echo -e "HTTP/1.1 200\r\n\r\n\r\n&#x3C;h1>PONG&#x3C;/h1>" > response
</code></pre>

<figure><img src="/files/LTE6eDjDFWECAFwqDIj2" alt=""><figcaption></figcaption></figure>

Isto é incrível!&#x20;

E se, ao invés de escrever no named pipe separadamente, o fizermos depois do tratamento do HTTP request? Sim, como sabemos que o request é enviado para o STDOUT, tudo o que temos de fazer é ler o STDOUT, processá-lo, e depois escrever no named pipe (response) adequadamente, para posteriormente ser enviado no socket como resposta.

```bash
$ mkfifo response
$ cat response | nc -lvN 8080 | handleRequest
```

Onde `handleRequest` será uma função bash que iremos implementar, a qual terá como principal função ler o HTTP request do STDOUT, processá-lo e depois escrever uma resposta dinâmica no response named pipe.

### Processando o HTTP request

Hora de iniciar a implementação do server com a funcionalidade mínima na função `handleRequest`:

```bash
#!/bin/bash

## Cria o named pipe FIFO, que irá representar a resposta HTTP
rm -f response
mkfifo response

function handleRequest() {
  ## Ler o HTTP request até a linha \r\n
  while read line; do
    echo $line
    trline=$(echo $line | tr -d '[\r\n]') ## Remove o \r\n do final da linha

    ## Interrompe o loop de leitura quando a linha for vazia, após a remoção
    ## do \r\n no fluxo anterior
    [ -z "$trline" ] && break
    
    ## Implementar processamento do request a partir desta linha...
  done

  echo -e "qualquer coisa" > response
}

## 1. cria o socket e fica à escuta de conexões na porta 8080
## 2. quando uma conexão é estabelecida, o HTTP request é redirecionado para o input
##    da função `handleRequest`
## 3. a função processa a mensagem do HTTP request e escreve resposta no FIFO
## 4. assim que o FIFO recebe a mensagem, esta é enviada como resposta HTTP no socket
## 5. a conexão com o client é encerrada e o socket é finalizado
cat response | nc -lvN 8080 | handleRequest
```

#### Processar o headline

Ainda dentro da função `handleRequest`, dentro do loop que faz a leitura de cada linha, e utilizando *expressões regulares*, vamos processar o headline, que é basicamente a primeira linha da mensagem HTTP:

```ruby
## Parses the headline
## e.g GET /login HTTP/1.1 -> GET /login
HEADLINE_REGEX='(.*?)\s(.*?)\sHTTP.*?'
[[ "$trline" =~ $HEADLINE_REGEX ]] &&
  REQUEST=$(echo $trline | sed -E "s/$HEADLINE_REGEX/\1 \2/")
```

Okay, mas apenas o headline é necessário? E quanto às outras linhas da mensagem HTTP?&#x20;

Para continuarmos com o fluxo, precisamos antes entender como funciona um login na web, o que será assunto para a próxima seção.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://web101.leandronsp.com/construindo-um-web-server-com-login-and-logout.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
