Skip to content

Enforce Connection: close for close-delimited responses in HTTP/1.1#13

Closed
blueyetisoftware wants to merge 1 commit intocosock:mainfrom
blueyetisoftware:fix-close-delimited-connection-check
Closed

Enforce Connection: close for close-delimited responses in HTTP/1.1#13
blueyetisoftware wants to merge 1 commit intocosock:mainfrom
blueyetisoftware:fix-close-delimited-connection-check

Conversation

@blueyetisoftware
Copy link
Contributor

Description

This PR addresses a potential hang issue in the Luncheon HTTP library when parsing responses that lack Content-Length or Transfer-Encoding headers on HTTP/1.1 keep-alive connections. The issue arises because the library correctly follows RFC 9112 by reading the response body until the connection closes, but non-compliant servers may not close keep-alive connections, leading to indefinite waits.

To resolve this, we enforce RFC 9112 Section 9.6, which states that servers MUST send Connection: close for any HTTP/1.1 message immediately followed by a connection close. Close-delimited responses (without explicit length indicators) inherently require the connection to close, so we now reject such responses if Connection: close is not present, preventing hangs on malformed servers.

This change improves robustness for embedded systems like SmartThings hubs while maintaining spec compliance for well-behaved servers.

Changes

  • Added HttpMessage:get_connection() method: Retrieves and normalizes the Connection header value (lowercased), returning nil if absent.
  • Modified HttpMessage:body_type():
    • Unified the logic to determine body type (close or chunked) without early returns.
    • Added a protocol violation check for HTTP/1.1 close-delimited responses: If Connection is not explicitly close, return an error instead of proceeding.
  • No breaking changes: The fix only affects invalid responses; valid ones continue to work.

Testing

  • Manual Testing: Verified that responses with Connection: close and close-delimiting work as before.
  • Error Cases: Confirmed that responses without Connection: close (or with keep-alive) now fail fast with a clear error message.
  • Regression: Existing tests should pass; no functional changes for compliant responses.

Related Issues

  • Fixes the hang described in the SmartThings community thread: Luncheon Response Bug API 16
  • Enforces RFC 9112 Section 9.6 for better protocol adherence.

Checklist

  • Code follows existing style and conventions.
  • Error messages are clear and actionable.
  • No performance impact on valid responses.
  • Tested with edge cases (no headers, various connection values).

- Add get_connection() method to retrieve Connection header
- Modify body_type() to check for protocol violation when close-delimited
  response lacks Connection: close header in HTTP/1.1
- Prevents hangs on keep-alive connections with malformed servers
@FreeMasen FreeMasen requested a review from cjswedes March 5, 2026 23:27
@FreeMasen
Copy link
Contributor

This looks good to me, I've added someone from ST to also review before merging to ensure this will get updated in the hub's libs

Manual Testing: Verified that responses with Connection: close and close-delimiting work as before.

Would you be able to provide any details about how you've done this testing to enable others to repeat it?

@blueyetisoftware
Copy link
Contributor Author

blueyetisoftware commented Mar 5, 2026

Based on conversation with @cjswedes on the ST forums, I think I am going to pullback on this PR. I misread the spec. The server SHOULD send a 'close', not MUST as I indicated above. My change would make the code non-compliant and overly strict.

@blueyetisoftware
Copy link
Contributor Author

Closing. Probably not appropriate for pure spec compliance. May be useful for a 'strict' mode at some point in the future. Thanks for the review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants