> For the complete documentation index, see [llms.txt](https://web101.leandronsp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://web101.leandronsp.com/construindo-um-web-server-com-login-and-logout.md).

# 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.
