https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3
바디 길이는 다음의 순서로 결정된다?
HEAD 리퀘스트의 리스폰스나, 1xx, 204, 304는 헤더필드와 관계 없이 바디가 있으면 안 된다.
always terminated by the first empty line after the header fields
CONNECT 메소드의 결과로 2xx를 보낼때는 헤더 필드 끝나고 바로 종료. Content-Length, Transfer-Encoding 무시
Transfer-Encoding 헤더가 있고, chunked trasfer coding이 마지막(final) encoding이면 메세지 body의 길이는 transfer coding이 데이터 완료됐다고 할때까지 읽고 해석함.
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Transfer-Encoding#예제
만약에 response에 Transfer Encoding 헤더가 있고, chunked transfer coding 마지막 encoding이 아니면, 서버가 closed 될 때 까지 커넥션 유지.
서버가 closed 될 때까지 커넥션을 유지한다는 말은 서버에서 데이터 다 보내주면 알아서 종료되기 때문에 모든 데이터를 다 받아왔다고 할 수 있음.
리퀘스트면 400 주고 커넥션 종료해야한다. 메세지 body 길이를 확실하게 알 수 없으므로.
클라이언트에게 리스폰스를 보내줄 수 없으면 connection은 유지됨
Transfer-Encoding과 Content-Length 헤더가 둘 다 있으면 Transfer-Encoding이 Content-Length 헤더 필드를(값이 아니다) 오버라이딩. 이런 경우는 smuggling 이나 response splitting일 가능성이 있음 그렇다면 에러로 처리해야 한다. 그리고 발신자는 다운스트림으로 보내기 전에 Content Length를 제거해야한다.
스머글링 참고 https://portswigger.net/web-security/request-smuggling/finding response splitting은 crlf 공격으로도 불림 https://www.hahwul.com/cullinan/crlf-injection/
아래와 같은경우 메세지 framing을 invalid로 하고 수신자는 unrecoverable error로 처리해야 한다*(MUST)*
Request message의 경우 서버는 반드시 서버는 400으로 응답하고 커넥션을 닫아야한다.
Response message를 프록시가 수신한 경우 프록시는 서버와 커넥션 닫고, response를 취소(discard)하고, 502 리스폰스(bad gateway) 클라이언트에 보내야함.
Response message를 user-agent가 받은 경우 커넥션을 닫고 응답을 취소해야 한다.
유효한 content-length 헤더 필드고 Transfer-Encoding이 없으면 해당 숫자 값이 메세지 바디의 옥텟 길이가 된다. 만약 길이만큼 받기 전에 발신자가 커넥션을 끊거나 수신자 타임아웃에 걸리면 수신자는 반드시 메세지가 불완전하다고 판단한 뒤 커넥션 종료해야한다.
구현 할 때 무한 루프 걸렸으면 타임아웃 걸어둬야 할 듯 예를 들어, content-length가 3이고 메세지가 aa만 왔을 때 1만큼 더 기다려야 하는데, 계속 안 오면 연결 강제로 끊어줘야 할 듯.
Request message이면서 위의 조건에 만족하는 사항이 없으면 메세지 바디 길이는 0으로(메세지 바디가 없는 것으로) 간주한다.
그것도 아니면 본문 길이가 없는 response message이다. 따라서 커넥션 닫히기 전까지 수신된 옥텟 수가 content-length가 된다.
클라이언트가 계산
수신자는 성공적으로 완료됐는지 네트워크 실패로 인해 부분적으로 수신한 뒤 close-delimited 메세지인지 검증할 방법이 없다. 따라서 서버는 인코딩이나 길이로 구분되는 메세지를 가능하면 보내줘야 한다*(SHOULD)*.
close-delimited 기능은 주로 HTTP/1.0과의 하위 호환을 위해 존재한다.
Content-Length를 재활용을 하거나 하면 close-delimited가 필요할 수 있다.
서버는 message body가 있지만 Content-Length가 없는 경우 요청을 거부하고 411(Length Required) 응답을 보낼 수 있다 .
Chunk 이외의 transfer encoding이 적용된 것이 아니고, 클라이언트가 메세지 길이를 알 수 있는 경우 유효한 Content-Length 헤더 필드를 사용해야 한다(SHOULD)
일부 서비스는 chunked transfer-encoding을 알고 있더라도 411로 응답하기 때문이다.
이게 일반적인데 이유는 서비스 호출 전에 컨텐츠 길이가 필요한 게이트웨이를 통해 구현되거나 서버가 처리를 하기 전에 전체 요청을 버퍼링할 수 없거나 버퍼링할 의사가 없기 때문이다.