https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3

바디 길이는 다음의 순서로 결정된다?

  1. HEAD 리퀘스트의 리스폰스나, 1xx, 204, 304는 헤더필드와 관계 없이 바디가 있으면 안 된다.

    always terminated by the first empty line after the header fields
    
  2. CONNECT 메소드의 결과로 2xx를 보낼때는 헤더 필드 끝나고 바로 종료. Content-Length, Transfer-Encoding 무시

  3. Transfer-Encoding 헤더가 있고, chunked trasfer coding이 마지막(final) encoding이면 메세지 body의 길이는 transfer coding이 데이터 완료됐다고 할때까지 읽고 해석함.

    https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Transfer-Encoding#예제

    https://datatracker.ietf.org/doc/html/rfc7230#section-4.1

    만약에 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/

  4. 아래와 같은경우 메세지 framing을 invalid로 하고 수신자는 unrecoverable error로 처리해야 한다*(MUST)*

    Request message의 경우 서버는 반드시 서버는 400으로 응답하고 커넥션을 닫아야한다.

    Response message를 프록시가 수신한 경우 프록시는 서버와 커넥션 닫고, response를 취소(discard)하고, 502 리스폰스(bad gateway) 클라이언트에 보내야함.

    Response message를 user-agent가 받은 경우 커넥션을 닫고 응답을 취소해야 한다.

  5. 유효한 content-length 헤더 필드고 Transfer-Encoding이 없으면 해당 숫자 값이 메세지 바디의 옥텟 길이가 된다. 만약 길이만큼 받기 전에 발신자가 커넥션을 끊거나 수신자 타임아웃에 걸리면 수신자는 반드시 메세지가 불완전하다고 판단한 뒤 커넥션 종료해야한다.

    구현 할 때 무한 루프 걸렸으면 타임아웃 걸어둬야 할 듯 예를 들어, content-length가 3이고 메세지가 aa만 왔을 때 1만큼 더 기다려야 하는데, 계속 안 오면 연결 강제로 끊어줘야 할 듯.

  6. Request message이면서 위의 조건에 만족하는 사항이 없으면 메세지 바디 길이는 0으로(메세지 바디가 없는 것으로) 간주한다.

  7. 그것도 아니면 본문 길이가 없는 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로 응답하기 때문이다.

이게 일반적인데 이유는 서비스 호출 전에 컨텐츠 길이가 필요한 게이트웨이를 통해 구현되거나 서버가 처리를 하기 전에 전체 요청을 버퍼링할 수 없거나 버퍼링할 의사가 없기 때문이다.