Asciinema: Pedido inválido para uploads de gravações> 4kb em CentOS (Python 3.4)

Criado em 7 jun. 2017  ·  58Comentários  ·  Fonte: asciinema/asciinema

Relatório de erro

Informação do sistema:

  • Versão usada: 1.4.0 (1.1.1 também tem o mesmo problema)
  • SO: CentOS Linux versão 7.3.1611
  • Versão Python: Python 3.4.5
  • Ferramentas de instalação: yum (do repositório EPEL)

Passos para reproduzir:

  1. asciinema upload asciicast.json

Comportamento esperado:

Arquivo carregado para asciinema.org

Comportamento real:

Mensagem de erro de impressão do cliente:

Error: Invalid request: <html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>

Informação adicional:

O cliente cria uma gravação interrompida se zsh ( 4.3.11 (x86_64-redhat-linux-gnu) no meu caso) for usado e oh-my-zsh estiver instalado. Se oh-my-zsh desativado ou bash usado como um shell, o cliente cria e carrega a gravação sem problemas.

Gravação JSON: https://gist.github.com/andyone/b2a883e8c3795a6ad393a715ff7a41df

compatibility help wanted hosting

Comentários muito úteis

Acabei de voltar para a configuração anterior (encerrando SSL no Nginx). Deixe-me saber se funciona para você agora @andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann

Todos 58 comentários

Acontece para mim também. Usando ZSH, mas não OMZ.

$ zsh --version
zsh 5.3.1 (x86_64-pc-linux-gnu)
$ asciinema --version
asciinema 1.4.0

tmpw6byrbv8-asciinema.json

Descobri que, se eu mudar o URL da API de HTTPS para HTTP, tudo funcionará bem.

Eu mudei a configuração do balanceador de carga ontem, então isso pode estar relacionado.

Consegui reproduzir isso no Centos 7 Vagrant VM. Acho que isso tem algo a ver com o balanceador de carga Brightbox (com terminação SSL, certificado automático Let's Encrypt) que usamos desde ontem.

@andyone @ThiefMaster pode tentar agora? Eu posso ter resolvido isso.

ainda obtendo 400

Acho que é um problema relacionado ao OpenSSL. Enviar dados com curl está ok porque curl usa NSS (Network Security Services) para trabalhar com SSL / TLS.

com balanceador de carga Brightbox

É uma solução baseada em nginx?

@andyone Acho que o balanceador de carga Brightbox usa Haproxy.

Posso reproduzir isso de forma consistente. Criei o Vagrantfile e as instruções: https://github.com/sickill/bb-lb-400

@andyone o problema não parece ser esta linha específica em sua gravação, mas o tamanho geral do arquivo json carregado.

Criei um proxy https://ascii.kaos.io baseado em webkaos (nginx melhorado com BoringSSL) com esta configuração . As gravações minhas e do

Aqui está o que eu sei até agora:

As solicitações HTTP vão bem por meio do balanceador de carga Brightbox, mas as HTTPS fornecem 400 Bad Request
para solicitação em que o corpo da solicitação é maior que cerca de 4 KB.

O interessante é que estamos obtendo 400 para HTTPS no CentOS. HTTPS no macOS funciona bem. (HTTP funciona bem em qualquer lugar).

Eu olhei mais fundo, tentei descobrir onde está a diferença. Usei o tcpdump para ver as solicitações no CentOS e no macOS (HTTP, presume-se que a solicitação em si esteja formatada da mesma forma que em HTTPS).

A única diferença parece ser 2 linhas vazias antes do corpo no macOS, 1 linha vazia no CentOS (provavelmente devido à versão ligeiramente diferente do urllib que vem com o Python 3 nesses sistemas operacionais):

CentOS:

POST /api/asciicasts HTTP/1.1
Accept-Encoding: identity
User-Agent: asciinema/1.4.0 CPython/3.4.5 Linux/3.10.0-514.16.1.el7.x86_64-x86_64-with-centos-7.3.1611-Core
Authorization: Basic <61 bytes of base64 encoded credentials>
Content-Length: 13582
Content-Type: multipart/form-data; boundary=c3f4e35afa4a4ce6b65b6420da09b46e
Connection: close
Host: asciinema.org

--c3f4e35afa4a4ce6b65b6420da09b46e
Content-Disposition: form-data; name="asciicast"; filename="asciicast.json"
Content-Type: application/json

<about 13 kb of json>

Mac OS:

POST /api/asciicasts HTTP/1.1
Accept-Encoding: identity
Content-Length: 13582
Host: asciinema.org
User-Agent: asciinema/1.4.0 CPython/3.6.1 Darwin/16.5.0-x86_64-i386-64bit
Content-Type: multipart/form-data; boundary=71d5b757e9d1451b9540dc286f74207d
Authorization: Basic <61 bytes of base64 encoded credentials>
Connection: close


--71d5b757e9d1451b9540dc286f74207d
Content-Disposition: form-data; name="asciicast"; filename="asciicast.json"
Content-Type: application/json

<about 13 kb of json>

Para ver como isso afeta as coisas, alterei temporariamente o "Tamanho do buffer de solicitação" no LB de 4096 (padrão) para 8192 (máximo) e de repente começou a funcionar bem em todos os lugares (todos os sistemas operacionais, HTTPS), yay!

Não estou muito confiante de que essa seja a solução definitiva porque, com o tamanho do buffer de 4096, isso é verdade:

  • Sou capaz de fazer uma solicitação POST com um corpo de 3 MB sem problemas
    HTTPS no macOS
  • Portanto, presumo que esse tamanho de buffer é para cabeçalhos e não para o corpo da solicitação (isso foi confirmado por John do Brightbox)
  • Sou capaz de fazer a solicitação POST com corpo de <4 KB sem problemas
    HTTPS em CentOS
  • NÃO consigo fazer a solicitação POST com corpo> 4KB por HTTPS no CentOS
  • Acima contradiz minha suposição sobre a aplicação de buffer apenas para cabeçalhos ...
  • Os cabeçalhos de solicitação são pequenos (~ 330 bytes) em todos os casos

Quando eu bato "tamanho do buffer de solicitação" para 8192, o tamanho do corpo e o protocolo
não importa e tudo funciona bem. Eu me pergunto se batendo
para 8192 estou apenas ganhando tempo (tornar menos pessoas afetadas) ou isso
resolve o problema completamente (em caso afirmativo, por quê?).

Entrei em contato com a Brightbox sobre isso, espero que eles possam explicar o que está acontecendo.

Atualizar o tamanho do buffer de 8192 no lado Brightbox: com este número ele funciona para mim no CentOS, mas ainda não funciona para @ThiefMaster .

Ops, desculpe.

Antes de colocar o tráfego no Brightbox LB, encerrei o SSL no Nginx e tudo funcionou bem por anos. Se funcionar com o proxy @andyone baseado em Nginx, pode sugerir que o Nginx é mais "indulgente" quanto à formatação do pedido, enquanto o Haproxy é mais estrito e o cliente asciinema formata o pedido incorretamente (para os padrões Haproxy) no Python 3.4 (e seus urllib, que é mais antigo que o 3.6.1 que uso no mac).

Posso verificar mais tarde com Haproxy, mas minha versão é construída com LibreSSL em vez de OpenSSL.

Minha teoria atual é esta:

Essa nova linha única antes dos cabeçalhos e do corpo não é suficiente para o LB terminar de ler os cabeçalhos (ele espera 2 novas linhas) e continua lendo todos os dados abaixo dela como cabeçalhos, contando bytes, que eventualmente excedem o tamanho máximo dos cabeçalhos. Se LB tiver alguma variável como bytes_read (bytes lidos do soquete), ele verifica seu valor após terminar de ler os cabeçalhos e, mais tarde, novamente após ler o corpo. Se você enviar um arquivo <4kb, ele nunca ultrapassará o limite de 4kb para cabeçalhos, e se você enviar> 4kb, ele o excederá.
(e isso só acontece em HTTPS)

Não faço ideia se é esse o caso, apenas pensando em voz alta 😀

Código-fonte atualizado para adicionar nova linha extra, verificada no CentOS e ainda falhar. Portanto, a teoria acima está errada.

Isso funciona no CentOS com HTTPS:

curl -v -X POST -u $USER:api-token https://asciinema.org/api/asciicasts -F [email protected]

* About to connect() to asciinema.org port 443 (#0)
*   Trying 109.107.38.233...
* Connected to asciinema.org (109.107.38.233) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*   subject: CN=asciinema.org
*   start date: Jun 07 09:12:00 2017 GMT
*   expire date: Sep 05 09:12:00 2017 GMT
*   common name: asciinema.org
*   issuer: CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US
* Server auth using Basic with user 'vagrant'
> POST /api/asciicasts HTTP/1.1
> Authorization: Basic <...hidden...>
> User-Agent: curl/7.29.0
> Host: asciinema.org
> Accept: */*
> Content-Length: 5658
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=----------------------------6ca3f3de6469

Então, talvez a lib SSL usada por Python seja diferente de curl e o problema esteja em algum lugar do SSL?

Eu penso que sim. Python usa OpenSSL, curl usa NSS.

@andyone o certificado para ascii.kaos.io não é Let's Encrypt?

RapidSSL SHA256withRSA

Normalmente, eu diria que falta o certificado raiz do CentOS para Let's Encrypt (ou algo parecido 😊), mas a conexão SSL está sendo feita e o erro está no nível do protocolo HTTP (400 Bad Request), então ... 👐

Se o certificado raiz para Let's Encrypt estiver faltando, ele não funcionará mesmo com curl.

Nosso balanceador de carga (Brightbox) realmente usa haproxy. Os documentos HTTP RFC e haproxy afirmam que um CRLF é necessário para separar os cabeçalhos do corpo:

https://github.com/haproxy/haproxy/blob/master/doc/internals/http-parsing.txt

É possível que você esteja enviando apenas um CR ou LF aqui, em vez de um CRLF completo?

@sickill Este é o proxy no HA-Proxy 1.7.5 com LibreSSL 2.5.0 - https://ascii-ha.kaos.io. As gravações minhas e do over-4k.json do seu repositório foram carregadas com sucesso através deste proxy.

@andyone ok. Então, você pode alterar tune.bufsize (https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#3.2-tune.bufsize) para 4096?

@johnl Eu verifiquei o CRLF e tudo está OK aqui.

Eu tcpdumped a solicitação no CentOS e no macOS novamente (por HTTP, novamente, assumindo que a carga útil HTTP é a mesma para HTTPS).

dump-centos.pcap.txt e dump-mac.pcap.txt contêm a captura tcpdump ( tcpdump -s 0 dst port 80 -w dump-centos.pcap.txt ).
dump-centos-hex.txt e dump-mac-hex.txt contêm dumps formatados em hexadecimal (via hexdump -C ).

dump-centos-hex.txt
dump-centos.pcap.txt
dump-mac-hex.txt
dump-mac.pcap.txt

Parece que em ambos os sistemas operacionais há CRLF usado para novas linhas e há uma linha em branco entre os cabeçalhos e o corpo.

No CentOS esquerdo, no macOS direito:

centos-mac-comparison

@sickill Config atualizado. over-4k.json enviado.

@andyone obrigado pela atualização. Parece que não adiciona o cabeçalho X-Forwarded-Proto (porque o URL de gravação retornado é http:// ). Você pode adicionar http-request set-header X-Forwarded-Proto https if { ssl_fc } ?

Esta é minha configuração:

frontend www-https
    bind 207.154.241.251:443 ssl crt /etc/ssl/private/kaos.pem
    reqadd X-Forwarded-Proto:\ https
    default_backend www-backend

backend www-backend
    server asciinema-backend asciinema.org:80

Onde devo adicionar esta linha?

@andyone Eu acho que precisa ir para a seção backend (eu não sou especialista em haproxy).

@andyone btw, Agradeço MUITO por você ajudar a depurar isso 😍 Obrigado!

não se esqueça de seguir em frente também. Isso deve replicar a configuração bem de perto, com as cifras SSL também:

    tune.bufsize 4096
    tune.ssl.default-dh-param 2048
    tune.maxrewrite 40

frontend www-https
    bind 207.154.241.251:443 ssl no-sslv3 crt /etc/ssl/private/kaos.pem ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
    reqadd X-Forwarded-Proto:\ https
    default_backend www-backend

backend www-backend
    server asciinema-backend asciinema.org:80
    mode http
    option forwardfor
    option httplog

Modifiquei a configuração para isso, mas sem sorte:

    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option                  http-server-close
    option                  forwardfor
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

frontend www-https
    bind 207.154.241.251:443 ssl crt /etc/ssl/private/kaos.pem
    reqadd X-Forwarded-Proto:\ https
    default_backend www-backend

backend www-backend
    http-request set-header X-Forwarded-Proto https
    server asciinema-backend asciinema.org:80

O cliente ainda retorna links com http:// .

Estou sempre feliz em ajudar a melhorar os serviços úteis 😉.

@johnl Esta é a configuração completa, todas as opções necessárias estão definidas nas seções defaults e global :

    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    tune.bufsize 4096

    # SSL configuration
    tune.ssl.default-dh-param 2048
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
    ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
    ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option                  http-server-close
    option                  forwardfor
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

frontend www-https
    bind 207.154.241.251:443 ssl crt /etc/ssl/private/kaos.pem
    reqadd X-Forwarded-Proto:\ https
    default_backend www-backend

backend www-backend
    http-request set-header X-Forwarded-Proto https
    server asciinema-backend asciinema.org:80

Se @andyone é configuração haproxy está agora muito perto de BB e nós ainda não pode reproduzir o problema, faz sentido tentar com Vamos Criptografar cert? Esta é uma das diferenças entre https://ascii-ha.kaos.io e https://asciinema.org.

Esta é uma das diferenças entre https://ascii-ha.kaos.io e https://asciinema.org.

Não. O BB LB pode ser construído com OpenSSL (eu uso LibreSSL).

Vou tentar adicionar o certificado Let's Encrypt para https://ascii-ha.kaos.io.

Feito - https://ascii.kaos.re
HA-Proxy 1.7.5 (c / LibreSSL 2.5.0) + certificado Let's Encrypt (criado por Certbot)
Config:

    tune.bufsize 4096
    tune.ssl.default-dh-param 2048
    tune.maxrewrite 40

frontend www-https
    bind 207.154.241.251:443 ssl no-sslv3 crt /etc/ssl/private/ascii.kaos.re.pem ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
    reqadd X-Forwarded-Proto:\ https
    default_backend www-backend

backend www-backend
    server asciinema-backend asciinema.org:80
    mode http
    option forwardfor
    option httplog

Parece que tudo funciona bem. over-4k.json carregado com sucesso.

Não tenho mais ideias para isso. Estou pensando em reverter para minha própria instância Nginx para balanceamento de carga e encerramento de SSL 🤕

Estou tentando reduzir isso a um único comando curl que pode reproduzir o problema, mas ainda não o consegui, alguém pode ajudar?

Estou postando um corpo de 5k, com um nome de usuário / senha de autenticação usando curl. Estou acessando um balanceador de carga Brightbox com um back-end de servidor web netcat, então posso ver o texto da solicitação bruta. Ele sempre passa - não pode fazer com que acione uma resposta de solicitação incorreta.

Se isso estiver sendo rejeitado pelo balanceador de carga, não precisarei de uma instância real do aplicativo no back-end, pois ela nunca deve ir tão longe - portanto, devemos ser capazes de reproduzir isso com curl e sem aplicativo.

Eu tentei curl no ubuntu e centos7, e com o openssl especificamente (observe que você pode especificar o comando --engine para curl para escolher qual lib sslib usar. Centos7 curl binários são construídos contra a maioria das opções)

@johnl obrigado por investigar isso.

Faz sentido usar o netcat como back-end para teste 👍

curl equivalente para asciinema upload over-4k.json é mais ou menos isto:

curl -v -X POST -u test:uuid4 https://asciinema.org/api/asciicasts -F [email protected]

(substitua uuid4 pelo resultado de python3 -c 'import uuid; print(uuid.uuid4())' )

E funciona com curl de fato ...

Eu comparei o tcpdump de asciinema upload e o curl acima e não há nada no nível do protocolo HTTP que pareça suspeito para mim. No entanto, alguns quadros tcp aparecem em locais diferentes (talvez mais / menos dados sejam enviados / cabem em cada pacote tcp).

Capturei a solicitação HTTP (para http://asciinema.org) com tcpflow no CentOS 7 VM:

sudo tcpflow -p -C -i eth0 port 80 >tcpflow-req.txt

Em seguida, em outro shell (na mesma VM), executei:

ASCIINEMA_API_URL=http://asciinema.org asciinema upload /vagrant/over-4k.json

Cortei a resposta dele, deixando apenas um pedido. Aqui está o que é enviado, byte por byte: tcpflow-req.txt

Eu reproduzi esta solicitação HTTP capturada contra asciinema. org: 80 com nc :

bash-4.4$ (cat tcpflow-req.txt; cat) | nc asciinema.org 80
HTTP/1.1 201 Created
Server: nginx
Date: Mon, 12 Jun 2017 13:30:03 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 48
Connection: close
Status: 201 Created
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Location: http://asciinema.org/a/4lgbbik7li4ywzqrfak0e7eku
ETag: "9beb7ac6bb5981f06fdc71df3947d8b0"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 2a8a8c75-ed06-4741-9adb-e5d276032ded
X-Runtime: 0.360858
Vary: Accept-Encoding
Strict-Transport-Security: max-age=15768000

http://asciinema.org/a/4lgbbik7li4ywzqrfak0e7eku

Tudo bom.

Agora, enviei SSL para asciinema. org: 443 :

(cat tcpflow-req.txt; cat) | openssl s_client -connect asciinema.org:443

Aqui está o resultado:

CONNECTED(00000003)
depth=1 /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/CN=asciinema.org
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFFDCCA/ygAwIBAgISBDhrp0YwV5NtleFOG+Zj61lQMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA2MDcwOTEyMDBaFw0x
NzA5MDUwOTEyMDBaMBgxFjAUBgNVBAMTDWFzY2lpbmVtYS5vcmcwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+/g237mVels4G9blsZlaeeiURbSp22eGO
T5OZ5As9NyuxSvRVEJrs4xk/RBEkCVgeZspSOmkRLwXG+FSMtjhbqIUt73AUKMdm
4DG+OwkVxjZatskL0wUWRcU7DmyW/Ls/OFJpPPcZ+pqu/v/ek99EiVNoAHJzXMXJ
ZsWy5KLE3fhkrlyMvdIkOkCK5zHOT95t0i8OmdaPIekPBa57VhvnDlUJsYyCF9GN
mP8Qg6OygexyULJGqBwiZ0BN2J6cYwChUlSvqFnkL4OzfixZ+mItuhl1b1vx/N5K
XMtPiM+nc/S+/liIWgtt7HIy9NmrOtSKbPTh3Bv/rfNdaiYx5CUHAgMBAAGjggIk
MIICIDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNAMhQNNwl+/bJjml9hrrHYzBxbf
MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMw
YTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9y
ZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9y
Zy8wLwYDVR0RBCgwJoINYXNjaWluZW1hLm9yZ4IVc3RhZ2luZy5hc2NpaW5lbWEu
b3JnMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsrBgEEAYLfEwEBATCB1jAm
BggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUF
BwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBv
biBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRo
IHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5j
cnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBABxmJxdQQCcy
FpCkiDrB+vonBUCLYSJtrFkmRdmj9W8/ADpC6M/EhYFOCgrO2cmhYfy1SxDAP5Hd
KIhd3p1F931MMXVcxYt2n6FiDJHN531qp6eBzjZsVIgHXS27PAV466IIMTydNQSe
reyDc9fi+q+ji1Gz89nI8lHIOlRt3dzVGT2J3oQidsm4ZuPNJFj4y8MUrbUAOOH6
YY4n395OKV7vWzl7VPKiCWx+zsv4bzr6IGUPlwqCN2e6cppPWE47ugnYsarINCHO
ie5lU4E2N0k2qVWe/+uYbwSUQ0nrEx8R078m6+6EjDkR4VLboLjuV5tGBgHsJLQB
CmLH6CmNCRE=
-----END CERTIFICATE-----
subject=/CN=asciinema.org
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
---
No client certificate CA names sent
---
SSL handshake has read 3436 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES128-SHA
    Session-ID: AC26CBF8D3719B1DE709A9A8AEAB43D20B14C62085A74604338C512CEA4472C5
    Session-ID-ctx:
    Master-Key: 0C59B1A2B6802D35FAD26DEE139043A853F3E62787E9AA743A8CAFDA95744DB73AB42B511F37EA7D6BB398A352938551
    Key-Arg   : None
    Start Time: 1497273777
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
HTTP/1.0 400 Bad request
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>

/ cc @johnl

@sickill Você pode verificar a mesma solicitação com https://ascii.kaos.re?

@andyone acabou de verificar. (cat tcpflow-req.txt; cat) | openssl s_client -connect ascii.kaos.re:443 - carregado com sucesso.

Eu fiz mais pesquisas aqui. curl em centos7 usa nss mas wget usa openssl. Posso enviar a solicitação com sucesso com curl ou wget. Posso até enviar usando a ferramenta python httpie (em python 3).

mas falha ao enviá-lo para openssl s_client via stdin

mas consegue enviá-lo para openssl s_client colando a solicitação nele, em vez de usar stdin!

Agora tenho quase certeza de que algo está enviando solicitações com terminações de linha LF em vez das terminações de linha CRLF exigidas, mas não tenho certeza do que. Acho que "openssl s_client" é uma ferramenta de teste ruim e está dificultando ter certeza do que está acontecendo.

Mas eu ainda não reproduzi isso com um cliente http adequado, seja usando nss ou openssl (curl no ubuntu usa openssl e funciona bem também, então confirmei isso duas vezes). Alguém mais gerencia isso?

Acabei de fazer alguns testes por conta própria e posso confirmar que o problema persiste com um comprimento de conteúdo de 4520, mas não com a mesma solicitação reduzida em 1000 caracteres ( Content-Length ajustados de acordo com as alterações feitas).

Os CRLF estão presentes em todos os meus testes e xxd confirma que eles são enviados pelo pipe.
Eu também poderia testar com o nc do OpenBSD (que suporta TLS).

Da documentação :

tune.bufsize
Define o tamanho do buffer para este tamanho (em bytes). Valores mais baixos permitem mais
sessões coexistam na mesma quantidade de RAM, e valores mais altos permitem que alguns
aplicativos com cookies muito grandes para funcionar. O valor padrão é 16384 e
pode ser alterado no momento da construção. É altamente recomendável não alterar isso
do valor padrão, pois valores muito baixos quebrarão alguns serviços, como
estatísticas e valores maiores que o tamanho padrão aumentarão o uso de memória,
possivelmente fazendo com que o sistema fique sem memória. Pelo menos o maxconn global
o parâmetro deve ser diminuído pelo mesmo fator que este é aumentado.
Se a solicitação HTTP for maior que (tune.bufsize - tune.maxrewrite), o haproxy irá
retornar erro HTTP 400 (solicitação incorreta). Da mesma forma, se uma resposta HTTP for maior
do que este tamanho, o haproxy retornará HTTP 502 (gateway incorreto).

Ao contrário do nginx, que não mantém a solicitação inteira na memória, mas a transmite em tempo real (AFAIK) ou, pelo menos, a armazena em um arquivo temporário.

Existe a opção no option http-buffer-request , que, se entendi direito, desativa exatamente esse comportamento (escrito para option http-buffer-request , sem no ):

Às vezes, é desejável esperar pelo corpo de uma solicitação HTTP antes
tomar uma decisão. Isso é o que está sendo feito por "balance url_param" para
exemplo. O primeiro caso de uso é armazenar solicitações de clientes lentos antes
conectando-se ao servidor. Outro caso de uso consiste em fazer o roteamento
decisão com base no conteúdo do corpo de solicitação. Esta opção colocada em um
frontend ou backend força o processamento HTTP a esperar até que todo o
corpo é recebido, ou o buffer de solicitação está cheio, ou o primeiro pedaço é
completo no caso de codificação em partes. Pode ter efeitos colaterais indesejáveis ​​com
alguns aplicativos que abusam de HTTP esperando transmissões sem buffer entre
o front-end e o back-end, então isso definitivamente não deve ser usado por
predefinição.

Eu acabei de bater nisso também. Parece-me que com o seu teste do mesmo conteúdo funcionando em HTTP, mas não em HTTPS, é improvável que haja falha nos tamanhos de buffer, a menos que algo entre seu cliente e o proxy esteja adicionando muitos cabeçalhos extras.

Mas talvez haja um bug em qualquer coisa que esteja encerrando suas conexões SSL de forma que corrompa um pouco os cabeçalhos.

Nesse caso, há uma opção que reduz a segurança do HAProxy, mas permite o tráfego HTTP menos compatível. Consulte https://stackoverflow.com/questions/39286346/extra-space-in-http-headers-gives-400-error-on-haproxy

Embora eu não defenda a redução da segurança como uma correção final, isso pode permitir que você mantenha o serviço enquanto o está depurando.

@peterbrittain no momento asciinema.org usa o balanceador de carga Brightbox Cloud, então eu não controlo sua configuração Haproxy. Costumávamos encerrar o SSL em nosso próprio Nginx e isso estava funcionando bem. Desde que mudei para BB LB, esse problema ocorre (para alguns). Você está experimentando no CentOS ou outro sistema?

Francamente, não tive nenhum problema com a solução anterior baseada em Nginx. O certificado SSL que tínhamos estava expirando, então pensei em Vamos criptografar. Uma vez que certificados LE têm vida curta, eles são melhor gerenciados automaticamente e o Brightbox LB faz isso por mim. Eu só queria economizar trabalho na configuração do LE e BB LB parecia ser a solução mais simples (já que asciinema.org é patrocinado pela Brightbox e funciona em sua ótima infraestrutura). Agora, acho que configurar o LE sozinho no Nginx provavelmente levaria 1/10 do tempo que já gastei resolvendo esse problema 😞😞😞

Ah. Não percebi a sutileza de quem era o dono de cada pedaço. Você teve sorte em obter diagnósticos do BB para este problema?

E em resposta à sua pergunta: minha caixa é uma CentOS 6 VM.

Eu também experimentei o problema de solicitação incorreta, usando asciinema 1.2.0 (versão do ubuntu 16.04 lts).

O hack curl fornecido acima funcionou, obrigado.

Acabei de descobrir que o mesmo arquivo produz uma solicitação incorreta na minha máquina Gentoo [1], mas não na minha máquina OpenBSD [2].
O OpenBSD faz o upload muito bem.
Acho que deveria haver uma investigação mais aprofundada sobre a diferença entre esses clientes.
A caixa do Gentoo suporta os seguintes destinos Python por ebuild:

PYTHON_TARGETS="python3_4 -python3_5"

No momento, não consigo testar o python3.5 facilmente, mas talvez isso já ajude.

Edit : Eu adicionei as versões do OpenSSL, esqueci completamente delas.

  • asciinema 1.4.0

    • executado usando python-exec 2.4.5

    • por sua vez, executando Python 3.4.6

  • OpenSSL 1.0.2l 25 de maio de 2017

  • asciinema 1.3.0

    • executado usando Python 3.6.0
  • LibreSSL 2.5.2

Acabei de voltar para a configuração anterior (encerrando SSL no Nginx). Deixe-me saber se funciona para você agora @andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann

@sickill Tenho apenas 85% de certeza de que é o mesmo arquivo que falhou antes, mas se for, você o corrigiu.

@sickill Funciona como um encanto para mim agora. 👍

Sim, funciona para mim (com asciinema upload ) também agora. Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

SR-Lut3t1um picture SR-Lut3t1um  ·  3Comentários

laughedelic picture laughedelic  ·  7Comentários

karelbilek picture karelbilek  ·  9Comentários

lebinh picture lebinh  ·  3Comentários

pfalcon picture pfalcon  ·  4Comentários