keepalive timer also closes a freshly dialed pooled connection during the HTTP/1.1 TLS upgrade

Đang mở
#938 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
58/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
erlang
Lĩnh vực
backend, networking

Hướng nghiên cứu

Start with the fresh-dial path in hackney_pool.erl:573-587 and 1005-1024, then trace connected and upgrade_to_ssl in hackney_conn.erl:845-869 and 996-1013. Compare the HTTP/1.1 and HTTP/2 upgrade branches, and run the pool-enabled HTTP/1 TLS-upgrade tests with a delayed handshake; done means a fresh connection is not closed by the keepalive timer during that handshake.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

hackney 4.7.4 (also current master).

#934 disarms the keepalive timer in the is_ready probe, which covers a reused pooled connection. A fresh dial does not reach is_ready:

  • handle_call({checkout, ...}) takes the none -> start_connection branch (hackney_pool.erl:573-587).
  • The new conn arms idle_timeout = keepalive_timeout on entry to connected (hackney_conn.erl:845-869). keepalive_timeout is capped at 2000 ms by min/2 in hackney_pool.erl:476-482 (an infinity value also collapses to 2000 because of Erlang term order), and start_connection/6 does not take a per-checkout override (hackney_pool.erl:1005-1024).
  • The HTTP/1.1 branch of upgrade_to_ssl returns keep_state and leaves that state_timeout running (hackney_conn.erl:1012-1013). The HTTP/2 branch cancels it via init_h2_after_upgrade (:2995-3007).
  • ssl:connect/3 at :996 blocks the gen_statem. If the TLS handshake takes longer than the remaining timer, the timer fires (:915-917), the conn goes to closed, and the caller's {request, ...} hits the catch-all and gets {error, invalid_state} (:2005-2006 on 4.7.4; {error, closed} on master after #936). No byte of the request has been written at that point.

Reproduced with a TCP proxy in front of api.stripe.com that delays the ClientHello: a 1900 ms delay succeeds, a 2200 ms delay fails with invalid_state, with pool enabled and protocols: [http1]. With prewarm_count: 0 the fresh-dial path is the only path, so the failure rate is simply the fraction of handshakes slower than ~2 s.

Suggested fix: arm the idle timer in connected(enter) only when owner =:= pool_pid (prewarm conns set owner => PoolPid at hackney_pool.erl:1367; fresh-dial conns set owner => Requester at :1024), cancel it in set_owner when the new owner is not the pool, and add the HTTP/2 branch's CancelIdle action to the HTTP/1.1 branch of upgrade_to_ssl.

Related: #916 (stuck in upgrade_to_ssl), #922 (handshake bounded by connect_timeout), #934, #936.

Ngôn ngữ chính
Erlang
Star
1.4k
Fork
458
Merge trung bình
11 giờ 32 phút
Pull request đã merge (30 ngày)
47

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của benoitc/hackney

Tất cả issue của benoitc/hackney

Issue tương tự

Thêm issue về Backend & API Design

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.