Resumo

  • No RFC 2068, a versão HTTP declarava o formato da mensagem e a capacidade máxima do emissor para compreender comunicações posteriores, não as funções executadas naquela troca.
  • Quando um proxy interpretava e recriava uma mensagem, tornava-se o emissor do próximo salto e precisava anunciar uma versão que ele próprio pudesse sustentar.
  • A evolução entre versões menores dependia de compatibilidade construída pelo emissor novo: removidos os campos desconhecidos pelo destinatário antigo, ainda precisava restar uma mensagem válida para ele.

Considere duas linhas registradas pelo mesmo proxy. Na entrada, GET /index HTTP/1.0. Na saída, GET /index HTTP/1.1. Os recursos pretendidos podem ser os mesmos, mas as mensagens não são uma peça intocada atravessando um tubo. O proxy recebeu uma unidade, tomou decisões e gerou outra.

Essa cena ajuda a ler o RFC 2068 sem transformar versão em marca de produto. HTTP/1.1 era uma declaração do emissor daquela mensagem: este é o formato usado neste salto e este é o nível que consigo compreender na continuação da conversa. Não significava que todas as funções de HTTP/1.1 estavam presentes, nem que o número deveria sobreviver sem mudanças até a outra ponta.

A lacuna entre nome e capacidade veio do HTTP/1.0

O RFC 1945, de maio de 1996, registrou o uso comum de HTTP/1.0 como documento informativo. Ele separou funções implementadas de maneira geralmente consistente daquelas raras ou inconsistentes. Portanto, a própria especificação já continha uma advertência histórica: duas aplicações chamadas HTTP/1.0 podiam não oferecer o mesmo conjunto prático.

A seção de versão já dizia que o número servia para indicar o formato da mensagem e a capacidade do emissor para entender comunicação HTTP futura, em vez das funções obtidas na troca corrente. O RFC 2068 preservou a ideia e explicou por que ela era necessária. Havia muitas aplicações parcialmente implementadas que se apresentavam como HTTP/1.0, dificultando a descoberta das capacidades reais entre participantes.

O primeiro dígito e o segundo não eram uma contagem uniforme. A versão maior mudaria quando o formato da mensagem fosse alterado. A menor poderia crescer quando novas funções adicionassem semântica ou capacidade sem trocar o algoritmo geral de análise. Acrescentar um valor a um campo já extensível, sem mudar o comportamento de comunicação, não exigia automaticamente uma nova versão.

O objetivo era manter um núcleo que participantes independentes pudessem analisar e, ao mesmo tempo, deixar espaço para evolução. O número só teria utilidade se seu emissor estivesse preso a obrigações verificáveis.

A capacidade anunciada não era o uso observado

O RFC 2068 exigia HTTP/1.1 na primeira linha das solicitações e respostas definidas pelo documento. Usar esse valor afirmava que a aplicação emissora era, no mínimo, condicionalmente compatível com a especificação. A versão da aplicação era o nível HTTP mais alto para o qual ela conseguia sustentar essa conformidade.

Essa regra produz três evidências distintas. A primeira é a sintaxe da mensagem que acaba de chegar. A segunda é o teto de capacidade declarado pelo emissor. A terceira é o conjunto de mecanismos efetivamente usados naquela mensagem.

Uma solicitação simples, sem corpo em chunks, sem negociação de conteúdo e sem controle de cache visível, podia ser HTTP/1.1. O número também preparava o receptor para uma resposta ou solicitação posterior. De modo inverso, a presença de HTTP/1.1 não provava que conexão persistente, transferência segmentada ou qualquer outra função tinha sido acionada.

O número tampouco autenticava o programa. Um software incompleto podia anunciar demais; o texto normativo dizia como uma declaração conforme deveria ser entendida, não oferecia uma assinatura criptográfica do código. A mesma linha não demonstrava entrega ao destino final, preservação de campos, aceitação de conteúdo, gravação durável ou sucesso da operação de negócio.

O intermediário não podia tomar emprestada a versão do cliente

Proxies e gateways mereceram uma regra explícita no RFC 2068. Como podiam interpretar, alterar e retransmitir mensagens, nunca deveriam enviar uma versão superior à própria capacidade real.

Ao receber uma solicitação mais nova do que sua implementação, o intermediário precisava escolher entre reduzir a versão, devolver um erro ou passar a atuar como túnel. Ao receber uma versão mais antiga, podia em certas condições elevá-la antes de encaminhar. Converter entre versões podia envolver adicionar ou retirar campos.

Logo, a capacidade do remetente anterior não seguia junto como um direito transferível. Um proxy HTTP/1.0 que copiasse HTTP/1.1 estaria prometendo ao próximo servidor algo que o próprio proxy não podia cumprir. Ao criar a saída, ele se tornava o novo emissor.

O RFC 2145, publicado em maio de 1997 para esclarecer interpretações conflitantes, resumiu a consequência: números de versão HTTP são componentes salto a salto, não de ponta a ponta. Um proxy não “encaminha” o número de uma solicitação ou resposta. O campo Via pode conservar separadamente os protocolos observados nos trechos anteriores, mas não transforma o número atual em histórico completo.

Por isso, uma captura no servidor de origem só informa a versão declarada por seu vizinho. Sem registros dos demais enlaces, não é possível concluir qual versão o navegador original usou com cada intermediário.

A versão nova precisava sobreviver sem os campos novos

O RFC 2145 registra que a política de versões tinha provocado confusão, debate e problemas de interoperabilidade. A primeira parte da correção foi impedir que a versão menor alterasse o significado de campos já conhecidos dentro da mesma versão maior. O número menor rotulava capacidade do emissor, não uma nova interpretação escondida da mensagem.

Um emissor mais recente podia enviar um campo que o receptor antigo desconhecia. Não podia, porém, depender de sua compreensão. Uma mensagem HTTP/1.1 enviada a HTTP/1.0, ou a um destino cuja versão era desconhecida, precisava continuar válida como HTTP/1.0 depois de removidos os campos ausentes na especificação antiga.

Esse teste de remoção colocava o custo da inovação no participante que escolhia a novidade. O destinatário antigo não precisava antecipar extensões futuras. O emissor novo tinha de manter uma mensagem residual completa e compreensível.

Campos desconhecidos também não eram todos iguais. Em geral, um proxy precisava preservá-los, porque uma aplicação adiante poderia entender a extensão. Se um campo estivesse listado em Connection, ele pertencia ao enlace atual e não devia atravessar para o próximo. A flexibilidade não alcançava dependências essenciais de framing. O RFC 2145 usou o caso de transferência em chunks: um servidor HTTP/1.1 não podia enviá-la em resposta a uma solicitação HTTP/1.0 e esperar que o cliente antigo simplesmente ignorasse o cabeçalho.

Compatibilidade, portanto, não era tolerar qualquer byte. Era garantir que a novidade pudesse desaparecer sem destruir a validade do núcleo antigo.

Uma especificação de esclarecimento também é evidência histórica

O RFC 2145 afirmou que não mudava o sentido pretendido de HTTP/1.0 ou HTTP/1.1; tornava definitiva a interpretação quando os textos anteriores fossem ambíguos. Sua existência prova que havia atrito entre documentação e implementação. Não fornece, contudo, nomes de produtos, contagem de falhas ou participação no tráfego.

O documento também disciplinou a escolha do número. Um cliente normalmente deveria enviar a versão mais alta para a qual fosse ao menos condicionalmente conforme, sem ultrapassar a versão maior conhecida do servidor. O servidor deveria responder com sua maior versão conforme cuja parte maior não superasse a recebida. Nenhum participante podia declarar uma versão que não implementasse.

Era possível baixar a versão para contornar um peer reconhecidamente defeituoso, mas só depois de observar o problema. Se o rebaixamento virasse padrão, implementações corretas não teriam acesso a capacidades novas e o protocolo seria moldado pelos participantes quebrados. Se o anúncio fosse inflado, o receptor passaria a depender de uma função inexistente.

Em 1999, o RFC 2616 manteve a separação e apontou para o RFC 2145. Em 2014, o RFC 7230 substituiu os dois e tornou explícito que a versão menor anuncia capacidade futura mesmo quando a mensagem atual usa apenas um subconjunto retrocompatível. Também registrou que a revisão do RFC 2068 para o RFC 2616 não aumentou a versão menor. Mudança de documento, mudança de obrigação e mudança de sinal no fio são eventos diferentes.

O RFC 9110, de 2022, separou a semântica comum de HTTP das sintaxes próprias de HTTP/1.1, HTTP/2 e HTTP/3. Essas versões maiores coexistem e não são apenas degraus em que a última apaga a anterior. Quando um intermediário encaminha uma mensagem, a versão passa a refletir o protocolo usado por ele naquele trecho; Via preserva outro tipo de informação sobre os trechos a montante.

Publicação, adoção e execução

A formulação posterior de Lu Heng — Especificação Inicial Mínima, Decisão Futura Localizada e Adoção Voluntária — oferece uma lente editorial para esse desenho. O núcleo compartilhado contém o indispensável à interoperabilidade. Cada participante que executa código decide localmente como tratar o conjunto compatível. Uma nova capacidade vira realidade operacional com implementação, validação e uso, não apenas com publicação.

Essa comparação não é prova de que os autores de HTTP anteciparam ou apoiaram as propostas institucionais e de registro distribuído de Lu Heng. Ela apenas impede que o relato confunda um RFC disponível, um número declarado, um software instalado, uma função usada e uma operação concluída.

O RFC 2068 não tentou fazer de HTTP/1.1 uma certidão universal. Fez algo mais durável: atribuiu a declaração ao emissor que realmente construía a mensagem e exigiu que a novidade deixasse um caminho válido para quem ainda operava na versão antiga.

Fontes