Ir para conteúdo
  • Visão geral do HTTP

       (1 análise)

    Gabriel Bezerra

    Criado como o protocolo para transmissão de hipertextos na World Wide Web, o protocolo HTTP ganhou bastante popularidade desde sua criação entre 1989 e 1991. É através desse protocolo que navegadores se comunicam com servidores para obter todos os textos, código e mídia que compõem os websites que acessamos.

    Para além do seu uso na web, dado sua simplicidade e extensibilidade; a disponibilidade de ferramentas e implementações em diversas linguagens de programação; e o fato de ser liberado pela maior parte dos firewalls e filtros de rede, o protocolo foi adotado como base de diversos outros protocolos e de interfaces entre aplicações e serviços.

    Neste artigo, exploraremos a história do protocolo, sua estrutura e funcionamento. Com esse conhecimento, poderemos entender melhor suas extensões e aplicações.

    História

    O protocolo HTTP (HyperText Transfer Protocol, ou "protocolo de transferência de hipertexto" em tradução livre) foi criado por Tim Berners-Lee e seu time, em 1989, como parte de sua proposta para a World Wide Web. A proposta se baseava em hipertextos -- textos com referências a outros textos que podem ser acessadas imediatamente -- e possuia quatro elementos básicos:

    • Uma linguagem para representação de documentos de hipertexto: HTML (HyperText Markup Language);
    • Um protocolo para transmissão desses documentos: HTTP (HyperText Transfer Protocol);
    • Um cliente para exibição desses documentos: o navegador ou browser;
    • Um servidor para disponibilização desses documentos.

    HTTP 0.9

    A primeira versão do HTTP era bastante simples e possuia apenas uma funcionalidade: obter um documento. As requisições eram enviadas em conexões TCP/IP e tinham o formato:

    GET /pagina.html

    As repostas consistiam apenas do documento em si:

    <html>exemplo de página em html</html>

    Apenas documentos HTML podiam ser transmitidos. Também não havia códigos de retorno. Em caso de erro, uma página com uma descrição do erro era eviada a fim de ser entendida pelo usuário. Ao final da transmissão do documento, a conexão era encerrada. Essa versão foi documentada em 1991, sendo chamada de HTTP 0.9.

    Desde então, o protocolo começou a evoluir via experimentação. Entre 1991 e 1995, um servidor e um navegador adicionavam funcionalidades e aguardavam para ver se ela obtinha tração. Um esforço de padronização foi então iniciado.

    HTTP 1.0

    Em 1996, a versão 1.0 foi padronizada com a publicação do RFC 1945. As principais adições dessa versão foram:

    • A informação de versão do protocolo foi adicionada à primeira linha da requisição, com o sufixo "HTTP/1.0";
    • Código de estado, ou código de retorno, foi adicionado à primeira linha da resposta, permitindo a sinalização de condições de erro;
    • Cabeçalhos foram adicionados à todas as mensagens, permitindo extensões ao protocolo e transmissão de metadados. Por exemplo, o cabeçalho "Content-Type" viabilizou a transmissão de outros tipos de conteúdo além de documentos HTML.

    HTTP 1.1

    Em 1997, poucos meses após a padronização da versão 1.0, com a publicação do RFC 2068 definiu-se a versão 1.1 do protocolo, também chamada HTTP/1.1. Em 1999 foi publicado o RFC 2616, com atualizações e melhorias sobre o RFC 2068. Em 2014, uma série de RFCs foi publicada detalhando e esclarecendo o RFC 2616: RFC 7230, RFC 7231, RFC 7232, RFC 7233, RFC 7234 e RFC 7235.

    As principais mudanças da versão 1.1 foram:

    • Reutilização de conexões para atendimento de diversas requisições, economizando recursos para a abertura das múltiplas conexões necessárias para obtenção dos vários documentos que compõem uma página;
    • O cabeçalho "Host" torna-se obrigatório, permitindo que websites de múltiplos domínios sejam hospedados simultaneamente em um mesmo servidor;
    • Pipelining, permitindo que diversas requisições fossem enviadas antes de as respostas serem recebidas: uma forma de diminuir o atraso para transmissão de documentos. Uma técnica não muito utilizada na prática;
    • "Chunked Transfer Encoding" ("codificação de transferência seccionada", em tradução livre), mecanismos de controle de caches e mecanismos de negociação de conteúdo entre cliente e servidor.

    HTTP 2.0

    Em 2015, baseado principalmente na experiência obtida com o protocolo experimental SPDY da Google, foi publicado o RFC 7540, padronizando a versão 2.0 do protocolo, também conhecida como HTTP/2.

    As principais diferenças do HTTP/2 se comparado ao HTTP/1.1 são:

    • É um protocolo binário em vez de textual;
    • É um protocolo multiplexado, isto é, diversas requisições e suas respectivas respostas dividem uma mesma conexão TCP/IP paralelamente. Essa funcionalidade substitui o pipelining do HTTP/1.1;
    • Compressão de cabeçalhos;
    • Alimentação de caches dos clientes pelo servidor antes mesmo dos clientes
    • Enviarem requisições para os respectivos recursos.

    HTTP 3.0

    No momento da escrita deste artigo, está em discussão a criação da versão 3 do HTTP. A principal modificação prevista para o HTTP/3 é o uso do protocolo de transporte QUIC no lugar de TCP como o protocolo de transporte para o HTTP.

    O foco das modificações nesta versão é desempenho. Por exemplo, tenta-se diminuir a quantidade de trocas de mensagens necessárias para o estabelecimento de conexões. O rascunho mais recente de sua especificação pode ser encontrado em draft-ietf-quic-http-34.

    Segurança em comunicações HTTP

    É importante notar que o protocolo HTTP, em todas as suas versões até então, não provê confidencialidade, integridade ou autenticidade das transmissões.

    Para obter essas propriedades de segurança, a Netscape Communications criou, em 1994, o HTTPS (HyperText Transfer Protocol Secure). Uma extensão ao HTTP em que, em vez de utilizar HTTP diretamente sobre uma conexão TCP/IP, a conexão TCP/IP é criptografada usando TLS (Transport Layer Security, "segurança de camada de transporte" em tradução livre), antigamente chamado de SSL (Secure Sockets Layer, "camada de sockets seguros" em tradução livre).

    O protocolo

    A sintaxe e a semântica do HTTP têm se mantido estável desde sua versão 1.1. As mudanças realizadas em versões posteriores ao HTTP/1.1 trataram-se principalmente de mudanças em relação à camada de transporte, e de extensões ao protocolo através da padronização de novos cabeçalhos.

    Por isso, cobriremos neste artigo a versão 1.1 do protocolo, considerando apenas sua estrutura básica. O conhecimento desta parte do protocolo poderá então ser usado para entender suas extensões e protocolos construídos com base nele.

    Modelo de comunicação

    O protocolo HTTP segue o modelo de cliente-servidor, em que o cliente abre uma conexão para o servidor, envia uma requisição e aguarda sua resposta.

    Ele é um protocolo de camada de aplicação e, apesar de ser classicamente implementado sobre TCP, funciona sobre qualquer protocolo de transporte que forneça entrega confiável de mensagens.

    Intermediários

    O HTTP é feito para que componentes intermediários na comunicação possam colaborar para a entrega de uma requisição e/ou de uma resposta. Os intermediários considerados na definição do protocolo são: proxies, gateways (ou reverse-proxies) e túneis.

    Proxies são intermediários escolhidos pelos clientes, normalmente via configuração local. Gateways são intermediários escolhidos pelo servidor, normalmente implementando caches ou balanceadores de carga. Tanto proxies como gateways podem alterar o conteúdo da comunicação HTTP. Túneis são intermediários que retransmitem mensagens entre duas conexões sem alterar seu conteúdo.

    URIs

    URIs (Uniform Resource Identifiers, "identificadores uniformes de recursos" em tradução livre), definidos pelo RFC 3986, são o meio usado para identificar recursos no HTTP. URIs são usados para direcionar requisições, indicar redirecionamentos e definir relacionamentos.

    Os "URI Scheme"s "http" e "https" são definidos pelo RFC 7230.

    Sessão HTTP

    Uma sessão HTTP é uma sequência de transmissões no formato: requisição-resposta. O cliente -- não necessariamente um navegador -- inicia uma requisição estabelecendo uma conexão TCP, normalmente na porta 80 do servidor; ou uma conexão TLS sobre TCP, normalmente na porta 443 do servidor. Em seguida, envia a mensagem de requisição ao servidor.

    O servidor, esperando a conexão, aguarda a mensagem de requisição do cliente. Ao recebê-la, processa-a e responde ao cliente enviando um código de estado seguido de sua resposta. A reposta do servidor pode conter o documento requerido, um erro ou outras informações.

    Como discutido na seção anterior, conexões podem ser reusadas para o envio de múltiplas requisições.

    Independentemente o reuso de conexões, o protocolo HTTP é um protocolo "stateless", isto é, informações de estado não são mantidas pelo receptor -- neste caso, o servidor -- entre requisições. Cada requisição pode ser entendida isoladamente.

    Para implementar manutenção de estado da sessão, é necessário utilizar-se extensões ao HTTP. Por exemplo, aplicações podem utilizar Cookies, parâmetros na URL ou parâmetros escondidos em formulários HTML.

    Mensagem HTTP

    As mensagens do protocolo HTTP são compostas por:

    • Uma linha inicial, cujo formato varia entre requisição e resposta;
    • Possivelmente uma sequência de cabeçalhos;
    • Uma linha vazia;
    • Possivelmente um corpo da mensagem.

    As linhas são separadas pelos caracteres "<CR><LF>": os caracteres "carriage return" e "line feed" da tabela ASCII, representados pelos valores 0x0D e 0x0A em hexadecimal ou os caracteres "\r\n" na notação de strings de C.

    Por exemplo, na mensagem:

    GET / HTTP/1.1
    Host: www.example.com
    User-Agent: curl/7.64.1
    Accept: */*

    Temos a linha inicial "GET / HTTP/1.1" os cabeçalhos "Host: www.example.com", "User-Agent: curl/7.64.1" e "Accept: */*", a linha vazia, e nenhum corpo. Já na mensagem:

    HTTP/1.1 301 Moved Permanently
    Server: nginx/1.14.2
    Content-Type: text/html
    Content-Length: 185
    Connection: keep-alive
    Location: https://www.example.com/
    
    <html>
    <head><title>301 Moved Permanently</title></head>
    <body bgcolor="white">
    <center><h1>301 Moved Permanently</h1></center>
    <hr><center>nginx/1.14.2</center>
    </body>
    </html>

    Temos a linha inicial "HTTP/1.1 301 Moved Permanently", os cabeçalhos "Server: nginx/1.14.2", "Content-Type: text/html", "Content-Length: 185", "Connection: keep-alive" e "Location: https://www.example.com/", a linha vazia, e o corpo "<html>...</html>".

    Cabeçalhos

    Os cabeçalhos são formados por pares chave-valor da forma:

    • Uma chave case-insensitive, isto é, ignorando maíusculas e minúsculas;
    • Um caractere ":" possivelmente seguido de espaços em branco;
    • Um valor;
    • Possivelmente espaços em branco.

    Cada cabeçalho é separado do próximo por uma quebra de linha contendo "<CR><LF>".

    Observe que nem a chave nem o valor do cabeçalho podem conter os caracteres "<CR><LF>", caso contrário um novo cabeçalho é iniciado. Caso o tipo de dado a ser a ser transmitido no cabeçalho possa conter quebras de linha, é necessário codificá-lo com uma codificação que não produza "<CR><LF>". Uma codificação comumente utilizada para isso é a codificação por cento, também chamada de codificação URL.

    Corpo da mensagem

    O corpo da mensagem é um campo opcional. Apenas alguns tipos de requisições e alguns tipos respostas permitem ou necessitam de um corpo de mensagem.

    A presença de um corpo de mensagem é sinalizado pelos cabeçalhos "Content-Length" ou "Transfer-Encoding". O primeiro é usado para sinalizar o número de bytes que compõem o corpo da mensagem, o segundo é usado quando se deseja transmitir um corpo de forma seccionada ("chunked") ou comprimida, por exemplo. Apenas um dentre "Content-Length" e "Transfer-Encoding" devem ser usados em uma mesma mensagem.

    Requisição

    As requisições HTTP são compostas de uma mensagem HTTP cuja linha inicial contém:

    • O método, ou verbo, que representa o comando a ser executado;
    • O recurso alvo da requisição;
    • A versão do protocolo: por exemplo, "HTTP/1.1".

    Além disso, em toda requisição, é necessário informar o cabeçalho "Host". Seu valor deve conter o nome de domínio do website ou servidor a ser acessado. O nome de domínio utilizado nesse cabeçalho deve resolver para um enderço IP do servidor.

    Usando novamente o exemplo da seção anterior,

    GET / HTTP/1.1
    Host: www.example.com
    User-Agent: curl/7.64.1
    Accept: */*

    A linha inicial dessa requisição contém o método "GET", o recurso "/" e a versão do protocolo "HTTP/1.1".

    Métodos

    Os métodos, ou verbos, do protocolo HTTP definem a operação que se deseja realizar com o recurso especificado.

    O RFC 7231 define os métodos:

    • GET: Requer uma representação do recurso especificado. No caso mais simples, apenas uma representação existe e ela é retornada. Múltiplas representações podem existir e serem negociadas através de cabeçalhos `Accept`, por exemplo;
    • HEAD: O mesmo que GET, mas sem que o servidor inclua o corpo da respota;
    • POST: Requer que o servidor processe o corpo da mensagem de requisição de acordo com as regras aplicáveis ao recurso especificado;
    • PUT: Requer que o servidor troque todas as representações atuais do recurso especificado, pelo conteúdo do corpo da mensagem de requisição;
    • DELETE: Requer que o servidor apague todas as representações atuais do recurso especificado;
    • CONNECT: Requer o estabelecimento de um túnel para o servidor identificado pelo recurso especificado. Seu uso é esperado apenas para controlar proxies HTTP.
    • OPTIONS: Requer informações sobre as opções de comunicação disponíveis para o recurso especificado. Em particular, o servidor responde com os métodos permitidos para aquele recurso. Caso suportado, pode também ser usado para obter informações sobre o próprio servidor ao se especificar o recurso "*";
    • TRACE: Requer que o servidor repita a mensagem recebida de volta para o cliente, para que o cliente possa investigar modificações na mensagem causadas por intermediários.

    Um outro método comumente aceito por servidores é definido no RFC 5789:

    • PATCH: Requer que o servidor altere todas as representações do recurso especificado de acordo com as modificações descritas no corpo da mensagem de requisição.

    O RFC 7231 define também o conceito de Métodos Seguros ("safe"): aqueles cuja semântica é essencialmente de somente leitura e, portanto, não devem causar nenhuma mudança significativa no servidor ou no recurso. Esse é o caso de "GET", "HEAD", "OPTIONS" e "TRACE". Essa definição é importante porque guia o comportamento esperado de clientes como navegadores, caches e robôs que varrem a web. Apesar disso, nada impede que aplicações incluam comportamentos perigosos, que não sejam apenas leitura ou que causem efeitos colaterais enquanto processam métodos seguros.

    Um outro conceito definido pelo RFC 7231 é o de Métodos Idempotentes: aquele cujo efeito de aplicá-los multiplas vezes é o mesmo que o de aplicá-los apenas uma vez. Esse é o caso dos métodos "PUT", "DELETE" e de todos os métodos seguros. A importância desta definição é que clientes podem reenviar essas requisições -- por exemplo, caso algo dê errado com a conexão -- sabendo que o efeito do reenvio vai ser o mesmo que caso o primeiro envio tenha sido bem sucedido. Assim como em relação aos métodos seguros, nada impede que aplicações incluam efeitos não idempotentes no processamento de métodos idempotentes.

    A lista completa de métodos padronizados pode ser encontrada em Hypertext Transfer Protocol (HTTP) Method Registry.

    Resposta

    As respostas HTTP são compostas de uma mensagem HTTP cuja linha inicial contém:

    • A versão do protocolo ("HTTP/1.1", por exemplo);
    • O código de estado, sinalizando se a requisição foi bem sucedida ou não;
    • Uma mensagem de estado, contendo uma curta descrição do código de estado.

    Usando novamente o exemplo da seção anterior,

    HTTP/1.1 301 Moved Permanently
    Server: nginx/1.14.2
    Content-Type: text/html
    Content-Length: 185
    Connection: keep-alive
    Location: https://www.example.com/
    
    <html>
    <head><title>301 Moved Permanently</title></head>
    <body bgcolor="white">
    <center><h1>301 Moved Permanently</h1></center>
    <hr><center>nginx/1.14.2</center>
    </body>
    </html>

    A linha inicial dessa resposta contém a versão do protocolo "HTTP/1.1", o código de estado "301" e a mensagem de estado "Moved Permanently". Essa mensagem também possui um documento HTML como corpo, que pode ser exibido ao usuário.

    Devido ao seu conteúdo, a linha inicial da resposta HTTP é também chamada de linha de estado.

    O cliente processa a resposta HTTP primariamente baseado em seu código de estado e depois baseado nos seus cabeçalhos. A mensagem de estado serve apenas de caráter informativo.

    Códigos de estado

    Códigos de estado são inteiros de três digitos que sinalizam o resultado do processamento da mensagem de requisição. Eles são organizados em classes baseadas em seu primeiro dígito:

    • 1xx (Informativo): A requisição foi recebida, continuando a processá-la;
    • 2xx (Bem sucedido): A requisição foi recebida, entendida e aceita;
    • 3xx (Redirecionamento): Mais ações do cliente são necessárias para completar a requisição;
    • 4xx (Erro do cliente): A requisição possui erros de sintaxe ou não pode ser atendida;
    • 5xx (Erro do servidor): O servidor não conseguiu atender uma requisição aparentemente válida;

    A lista de códigos de estado é extensível. Clientes não precisam conhecer todos os códigos de estado, porém devem poder reconhecê-los por sua classe baseado em seu primeiro dígito.

    A lista completa de códigos de estado padronizados pode ser encontrada em Hypertext Transfer Protocol (HTTP) Status Code Registry.

    Exemplo

    Para exemplificar o que vimos até agora, podemos experimentar o protocol manualmente usando o comando "netcat" (também representado pelo comando "nc") ou pelo "telnet".

    Para isso, primeiro executamos "nc www.example.com 80" para nos conectarmos à porta "80" do servidor em "www.example.com".

    $ nc www.example.com 80

    Agora escrevemos nossa mensagem de requisição: um método "HEAD" para o recurso "/":

    HEAD / HTTP/1.1
    Host: www.example.com

    Note que é necessário enviar uma linha em branco, marcando o final dos cabeçalhos e, no caso do método "HEAD", também o final da requisição.

    O servidor então nos responde com a mensagem de resposta:

    HTTP/1.1 200 OK
    Content-Encoding: gzip
    Accept-Ranges: bytes
    Age: 327597
    Cache-Control: max-age=604800
    Content-Type: text/html; charset=UTF-8
    Date: Fri, 14 May 2021 11:50:22 GMT
    Etag: "3147526947+ident"
    Expires: Fri, 21 May 2021 11:50:22 GMT
    Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
    Server: ECS (nyb/1D2A)
    X-Cache: HIT
    Content-Length: 648

    Podemos reusar a mesma conexão para enviar a próxima mensagem de requisição. Desta vez tentaremos um "POST" para o recurso "/", porém mal-formado, faltando o corpo da mensagem:

    POST / HTTP/1.1
    Host: www.example.com

    O servidor então nos responde com o erro:

    HTTP/1.1 411 Length Required
    Content-Type: text/html
    Content-Length: 357
    Connection: close
    Date: Mon, 17 May 2021 02:19:46 GMT
    Server: ECSF (nyb/1D13)
    
    <?xml version="1.0" encoding="iso-8859-1"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
            <title>411 - Length Required</title>
        </head>
        <body>
            <h1>411 - Length Required</h1>
        </body>
    </html>

    Note que, como é de se esperar, visto que enviamos uma requisição mal-formada, o código de estado se refere a um erro da classe "4xx" (erro do cliente).

    Abaixo o que se espera da comunicação completa:

    $ nc www.example.com 80
    HEAD / HTTP/1.1
    Host: www.example.com
    
    HTTP/1.1 200 OK
    Accept-Ranges: bytes
    Age: 552546
    Cache-Control: max-age=604800
    Content-Type: text/html; charset=UTF-8
    Date: Mon, 17 May 2021 02:19:31 GMT
    Etag: "3147526947"
    Expires: Mon, 24 May 2021 02:19:31 GMT
    Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
    Server: ECS (nyb/1D13)
    X-Cache: HIT
    Content-Length: 1256
    
    POST / HTTP/1.1
    Host: www.example.com
    
    HTTP/1.1 411 Length Required
    Content-Type: text/html
    Content-Length: 357
    Connection: close
    Date: Mon, 17 May 2021 02:19:46 GMT
    Server: ECSF (nyb/1D13)
    
    <?xml version="1.0" encoding="iso-8859-1"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
            <title>411 - Length Required</title>
        </head>
        <body>
            <h1>411 - Length Required</h1>
        </body>
    </html>

    Caso queira experimentar outros métodos, abaixo seguem alguns exemplos de mensagens de requisição para enviar.

    GET / HTTP/1.1
    Host: www.example.com

     

    OPTIONS / HTTP/1.1
    Host: www.example.com

    Caso queira testar com outros servidores, altere tanto o endereço ao qual se conecta no "netcat" ou "telnet", como o valor do cabeçalho "Host" para o servidor ao qual está se conectando.

    Referências


    • Agradecer 2

    Feedback do Usuário

    Participe da conversa

    Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.
    Nota: Sua postagem exigirá aprovação do moderador antes de ficar visível.

    Visitante

    • Isso não será mostrado para outros usuários.
    • Adicionar um análise...

      ×   Você colou conteúdo com formatação.   Remover formatação

        Apenas 75 emojis são permitidos.

      ×   Seu link foi automaticamente incorporado.   Mostrar como link

      ×   Seu conteúdo anterior foi restaurado.   Limpar o editor

      ×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.


    Andre Silva

       2 de 2 membros acharam esta análise útil 2 / 2 membros

    Excelente artigo sobre o funcionamento básico e evolução do protocolo, essencial para quem deseja atuar com segurança Web.

    • Curtir 2
    Link para a análise
    Compartilhar em outros sites


×
×
  • Criar Novo...