엔터티와 인코딩

엔터티와 인코딩

목차

HTTP는 매일 수십억 개의 미디어 객체를 실어 나른다.
HTTP는 콘텐츠를 잘 나르기 위한
잘 라벨링된 엔터티를 사용한다.

  • 엔터티와 엔터티 헤더들
  • 웹상의 화물을 수송하기 위해 어떤일을 하는지
  • HTTP가 어떻게 콘텐츠 크기, 타입, 인코딩에 대한 필수적인 값들을 제공하는지
  • 복잡하지만 강력한 기능을 알아본다.
    HTTP 엔터티, 범위요청(range request), 델타 인코딩(delta encoding), 요약(digest), 청크 인코딩(chunked encoding)

엔터티에 대하여

1. 메세지는 컨테이너, 엔터티는 화물

  • 엔터티는 엔터티헤더 + 엔터티 본문의 조합

1.1 엔터티 헤더 (참고)

  • 3가지 종류의 헤더가 있다
    1. 엔터티 정보헤더,
    2. 콘텐츠 헤더,
    3. 엔터티 캐싱 헤더

1. 엔터티 정보헤더

  1. Allow : 이 리소스에 대해 어떤 요청 메서드가 허용되는지

2. 콘텐츠 헤더

  1. Content-Type : 엔터티에 의해 전달된 객체의 종류
  2. Content-Length : 전달되는 메세지의 길이나 크기
  3. Content-Language : 전달되는 객체와 가장 잘 대응되는 자연어
  4. Content-Encoding : 객체 데이터에 대해 행해진 변형 (압축 등)
  5. Content-Location : 요청 시점 기준으로, 객체의 또 다르 위치
  6. Content-Range : 이 엔터티가 부분 엔터티라면, 이 헤더는 이 엔터티가 전체에서 어느 부분에 해당하는지 정의한다.
  7. Content-MD5 : 엔터티 본문의 콘텐츠에 대한 체크섬(중복검사의 한 형태)

3. 엔터티 캐싱 헤더

  1. Last-Modified : 서버에서 이 콘텐츠가 생성 혹은 수정된 날
  2. Expires : 이 엔터티 데이터가 더 이상 신선하지 않은 것으로 간주되기 시작하는 날짜와 시각
  3. ETag : 이 인스턴스에 대한 고유한 검사기

1.2 엔터티 본문

  • 엔터티 본문은 가공되지 않은 데이터만을 담고 있다. raw data
  • 다른 정보들은 모두 헤더에 담겨 있다.
  • 엔터티본문은 CRLF (캐리지 리턴 + 개행) 줄 바로 다음부터 시작한다.

2. Content-Length 엔터티의 길이

  • 메세지의 엔터티 본문의 크기를 바이트 단위로 나타낸다.
  • 어떻게 인코딩 되었든 상관없이 크기를 표현할 수 있다.
    • gzip으로 압축된 텍스트 파일이라면 => 원래 크기가 아니라 압축된 후의 크기
  • 엔터티 본문을 포함한 메세지에서는 필수적으로 있어야 한다.
    • 서버 충돌로 인해 메세지가 잘렸는지 감지하고자 할때
    • 지속 커넥션을 공유하는 메세지를 올바르게 분할하고자 할때 필요

2.1 잘림 검출

  • 옛날 버전의 HTTP: 커넥션이 닫힌 것을 보고 메세지가 끝났음을 인지
    • Content-Length가 없다면 클라는
      1. 커넥션이 정상적으로 닫힌 것인지,
      2. 메세지 전송 중에 서버에 충돌이 발생한 것인지 구분하지 못함
    • 잘림을 검출하기 위해 Content-Length가 필요로 했다.
  • 메세지 잘림은 캐싱 프락시 서버에서 특히 취약하다.
    1. 캐시가 잘린 메세지를 수신했으나 잘렸다는 것을 인식하지 못했다면
    2. 캐시는 결함이 있는 콘텐츠를 저장하고
    3. 계속 제공하게 될 것이다.
  • 캐싱 프락시 서버는 명시적으로 Content-Length 헤더를 갖고 있지 않은 HTTP본문은 보통 캐시하지 않는다.

2.2 잘못된 Content-Length

  • 공식적으로 HTTP/1.1 사용자 에이전트는 잘못된 길이를 받고 그 사실을 인지했을 때 사용자에게 알려주게 되어 있다.

2.3 Content-Length와 지속커넥션

  • Content-Length는 지속커넥션을 위해 필수다.
  • 만약 응답이 지속커넥션을 통해서 온 것이라면, 또 다른 HTTP 응답이 즉시 그 뒤를 이을 것이다.
  • Content-Length 헤더는 클라에게 메세지 하나가 어디서 끝나고 다음 시작은 어디인지 알려주는데,
  • 커넥션이 지속적일경우 클라가 커넥션이 닫힌 위치를 근거로 메세지의 끝을 인식하는 것은 불가능하므로,
    Content-Length로 시작과 끝을 가늠한다.
  • 때문에 지속커넥션에서는 Content-Length는 필수이다.
    • 다만, 청크인코딩은 지속커넥션으로 이루어지는데, 이때 Content-Length헤더는 없다.

2.4 콘텐츠 인코딩

  • HTTP는
    보안을 강화하거나
    압축을 통해 공간을 절약할 수 있도록,
    엔터티 본문을 인코딩할 수 있게 해준다.
  • 인코딩 될 경우 Content-Length 헤더는 인코딩된 본문의 길이를 바이트 단위로 정의한다.

2.5 엔터티 본문 길이 판별을 위한 규칙

switch (true)

  1. 본문을 갖는 것이 허용되지 않은 특정타입의 HTTP 메세지
    • Content-Length는 무시된다.
    • ex_ HEAD 메서드
  2. 메세지가 Transfer-Encoding 헤더를 포함하고 있다면
    • 엔터티는 ‘0 바이트 청크’라 불리는 특별한 패턴으로 끝나야 한다.
  3. 메세지가 Content-Length 헤더를 갖는다면
    • 본문의 길이를 담게 된다.
    • Transfer-Encoding가 identity가 아닌값을 포함한 메세지를 받았을 경우 Content-Length는 무시된다.
  4. (Content-type: multipart/byteranges) && (Content-Length가 정의되어있지 않다면)
    • 멀티파트 메세지의 각 부분은
      각자 스스로의 크기를 정의할 것이다.
    • 멀티파트 유형은 자신의 크기를 스스로 결정할 수 있는 유일한 엔터티 본문 유형이다.
    • 수신자가 이것을 해석할 수 있다는 사실을 송신자가 알기 전까지 보내지 말아야 한다…
    • RFC7230 때 삭제됨.
  5. (default)
    • 엔터티는 커넥션이 닫힐 때 끝난다.
    • Content-Length를 요구하고 싶을 경우 411 Length Required 응답을 보냄

3. 미디어 타입과 Charset

  • Content-Type은 엔터티 본문의 MIME 타입을 기술한다. IANA에 정리되어있는 MIME타입

    IANA: 인터넷 할당 번호 관리기관 Internet Assigned Numbers Authority

  • 주타입: application, audio, font, example, image, message, model, multipart, text, video

3.1 텍스트 매체를 위한 문자 인코딩

Content-Type: text/html; charset=iso-8859-7

  • 엔터티의 비트 집합을 텍스트 파일의 글자들로 변환하기 위한 charset 매개변수가 있다.

3.2 멀티파트 미디어 타입

  • 서로 붙어있는 여러 개의 메세지를 포함하며, 하나의 복합 메세지로 보내진다.
  • 각 구성요소는 자족적으로 자신에 대해 서술하는 헤더를 포함한다.
  • HTTP는 일부의 경우에 지원한다
    1. 폼을 채워서 제출할때
    2. 문서의 일부분을 실어 나르는 범위 응답을 할 때

1. 멀티파트 폼 제출 multipart/form-data

1
Content-Type: multipart/form-data; boundary=[abcdefghijklmnopqrstuvwzyz]
  • boundary는 본문의 서로 다른 부분을 구분하기 위한 구분자로 쓰인다.

2. 멀티파트 범위 응답 multipart/byteranges

  • 범위 요청에 대한 HTTP 응답 또한 멀티파트가 될 수도 있다.
  • 각각 다른 범위를 담고 있는 멀티파트 본문이 함께 온다.
  • multipart/byteranges는 브라우저로 회신하는 부분적인 응답 전송의 컨텍스트 내에서 사용된다.
  • 206 Partial Content 상태 코드가 전송된 경우,
    MIME 타입은 문서가 각각의 요청된 범위들 중 하나인 몇 가지 파트들로 구성되어 있음을 알려주기 위해 사용된다.
  • 다른 멀티파트 타입처럼, Content-Type은 경계선 문자열을 정의하기 위해 boundary 디렉티브를 사용한다.
    각각의 다른 파트들은 문서의 실제 타입을 가진 Content-Type 헤더와 그들이 나타내는 범위를 가진 Content-Range를 지니고 있다.

전송 전 ~ 전송 후

1. 엔터티 요약 Content-MD5

  • 여러가지 이유로 메세지의 일부분이 전송 중에 변형되는 일이 일어난다.
  • 송신자는 최초 엔터티가 생성될 때 데이터에 대한 체크섬을 생성할 수 있다.
  • 수신자는 모든 의도하지 않은 엔터티의 변경을 잡아내기 위해, 그 체크섬으로 기본적인 검사를 할 수 있다.
  • Content-MD5 헤더는 서버가 엔터티 본문에 MD5 알고리즘을 적용한 결과를 보내기 위해 사용된다.
    • 응답을 처음 만든 서버만이 Content-MD5헤더를 계산해서 보낼 것이다.
    • 중간에 있는 프락시와 캐시는 그 헤더를 변경하거나 추가하지 않을 것이다. (건드릴 경우 무결성 검증 목적을 손상시킴)
  • Content-MD5 헤더는
    콘텐츠 인코딩은 끝났지만,
    전송 인코딩은 아직 적용하지 않은 엔터티 본문에 대한 MD5를 담고 있다.
    • 메세지의 무결성을 검증하려는 클라는 먼저 전송 인코딩을 디코딩하고
    • 그 디코딩 된 엔터티 본문에 MD5를 계산해야 한다.
    • 문서를 gzip 알고리즘으로 압축하여 청크 인코딩으로 보냈다면, MD5 알고리즘은 압축된 본문 전체에 대해 수행된다.
  • MD5는 문서의 위치를 빠르게 알아내고, 콘텐츠의 중복저장을 방지하기 위한 해시테이블의 키로 이용될 수 있다.

    Content-MD5 헤더는 그다지 자주 전송되지 않는다.

2. 콘텐츠 인코딩 Content-Encoding

  • 전송시간을 줄이기 위해 압축하거나
  • 보안을 위해 콘텐츠를 암호화하거나
    할때 사용한다.
  • 콘텐츠 인코딩은 콘텐츠 포맷과 연관되어있다.
  1. 과정
  2. 유형
  3. 관련 헤더

1. 과정

  1. 웹서버가 원본 Content-Type과 Content-Length 헤더를 수반한 원본 응답 메세지를 생성
  2. 콘텐츠 인코딩 서버가 인코딩된 메세지 생성 (원서버 or 프록시)
    • Content-Length는 변경된다.
    • 콘텐츠 인코딩 서버는 어떤 방식으로 인코딩했는지 정보가 담겨있는 Content-Encoding 헤더를 인코딩된 메세지에 추가
      수신자가 디코딩할 수 있도록 한다.
  3. 수신자는 인코딩된 메세지를 디코딩하고 원본을 얻는다.

모던 브라우저에는 gzip 압축해제를 자동으로 해준다. 참고

2. 유형

  • 표준 콘텐츠 인코딩 유형이 정의되어있음. (IANA를 통해 표준화됨)
  • 커스텀으로 확장 인코딩을 추가하는걸 허용해놓음
  • gzip, compress, deflate 인코딩은 전송되는 메세지의 크기를 정보으 손실 없이 줄이기 위한 무손실 압축 알고리즘이다.

Content-Encoding: {유형}

  1. gzip : GNU zip 인코딩이 적용되었음을 의미
  2. compress: 유닉스 파일 압축 프로그램인 compress가 실행되었음을 의미
  3. deflate : zlib 포맷으로 압축되었다는 의미
  4. identity : 어떤 인코딩도 수행되지 않았음을 의미. (Content-Encoding 헤더가 존재하지 않는다면, 이 값인 것으로 간주)

3. Accept-Encoding 헤더

  • 서버에서 클라가 지원하지 않는 인코딩을 사용하는 것을 막기 위해,
    클라가 자신이 지원하는 인코딩의 목록을 Accept-Encoding 헤더에 포함한다.
  • 인코딩에 Q(quality)값을 매개변수로 더해
    선호도를 나타낼 수 있다.
    • Q의 범위는 원치않음 0.0 ~ 가장선호 1.0 사이이다.
      1
      2
      3
      4
      5
      Accept-Encoding: compress, gzip
      Accept-Encoding:
      Accept-Encoding: *
      Accept-Encoding: compress; q=0.5, gzip; q=1.0
      Accept-Encoding: gzip; q=1.0, identiy; q=0.5, *; q=0

3. 전송 인코딩과 청크 인코딩 Transfer-encoding

  • 메세지 데이터가 네트워크를 통해 전송되는 방법을 바꾸기 위해

3.1 안전한 전송

  • 역사적으로, 전송 인코딩은 안전한 전송을 위해 존재했다.
  • HTTP에서 전송된 메세지의 본문이 문제를 일으킬 수 있는 이유
    1. 알수 없는 크기: 몇몇 게이트 웨이 어플리케이션 or 콘텐츠 인코더는 메세지 본문의 최종 크기를 판단할 수 없다.
    2. 보안 : 메세지 콘텐츠를 보내기 전에, 전송 인코딩을 사용해 알아보기 어렵게 뒤섞어버리는 방법도 있다. SSL이 있어서 전송 인코딩 보안은 흔하지 않다.

3.2 Transfer-encoding 헤더

  • 전송 인코딩을 제어하고, 서술하기 위해 정의된 헤더는 2개
  • 최신 HTTP 명세는 오직 하나의 전송 인코딩, 청크 인코딩만을 정의했다.
  • 어떤 형태의 전송 인코딩을 선호하는지 표현하는 Q값을 가질 수 있다.
1
2
3
4
GET /new_products.html HTTP/1.1
Host: feel5ny.github.io
User-Agent: Mozilla/4.61 [en] (WinNT; I)
TE: trailers, chunked
1
2
3
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: Apache/3.0
  1. Transfer-encoding
    : 안전한 전송을 위해, 어떤 인코딩이 메세지에 적용되었는지 수신자에게 알려준다.
  2. TE
    : 어떤 확장된 전송 인코딩을 사용할 수 있는지 서버에게 알려주기 위해, 요청 헤더에 사용한다.

3.3 청크 인코딩

  • 메세지를 일정 크기의 청크 여럿으로 쪼갠다.
  • 서버는 각 청크를 순차적으로 보낸다.
  • 청크 인코딩을 이용하면, 메세지를 보내기 전에 전체 크기를 알 필요가 없어진다.
  • 청크 인코딩은 본문이 아닌, 메세지의 속성이다.
    • 멀티파트 인코딩은 본문의 속성, 청크 인코딩과는 완전 분리되어있다.

청크 인코딩과 지속 커넥션

  • 지속커넥션에서는, 본문을 쓰기 전에 만드시 Content-Length 헤더에 본문의 길이를 담아서 보내줘야 한다.

  • 청크 인코딩은 서버가 본문을 여러 청크로 쪼개 보낼 수 있게 해줌으로써

    1. 동적으로 본문이 생성되면서,
    2. 서버는 그 중 일부를 버퍼에 담은 뒤,
    3. 그 한 덩어리를 그의 크기와 함께 보낼 수 있다.
    4. 서버는 크기가 0인 청크로 본문이 끝났음을 알리고
    5. 다음 응답을 위해 커넥션을 열린 채로 유지할 수 있다.
  • 청크 인코딩은

    • 응답 헤더 블록으로 시작하고
    • 이어서 청크의 스트림이 온다.
      • 각 청크는 길이값과 각 청크에 대한 데이터를 담고 있다.
      • 길이값과 청크 데이터는 <CR><LF>로 분리된다.
      • 마지막 청크는 본문의 끝을 의미하기 위해 길이가 0 이다.
    1
    2
    27<CR><LF>
    블라블라블라 ~
    1
    0<CR><LF>
  • 클라 또한 청크 인코딩된 데이터를 서버로 전송한다.

청크 인코딩된 메세지의 트레일러

  • 다음 중 하나 이상 조건을 만족하면 청크 메세지에 트레일러를 추가할 수 있다.
    1. 클라의 TE 헤더가 트레일러를 받아들일 수 있음을 나타내고 있는 경우
    2. 트레일러가 응답을 만든 서버에 의해 추가되었으며,
      트레일러의 콘텐츠는 클라가 이해하고 사용할 필요가 없어서 무시하고 버려도 되는 경우
  • 트레일러에는 본문의 콘텐츠가 먼저 생성되어야 한다거나 하는 등의 이유로

메세지 시작 시점에서 그 값을 알 수 없는 추가적인 헤더 필드를 담을 수 있다.

  • 트레일러로 보낼 수 있는 헤더의 예로 Content-MD5 헤더가 있다.
  • Transfer-Encoding, Trailer, Content-Length를 제외한 어떤 HTTP 헤더도 트레일러로 보낼 수 있다.

콘텐츠와 전송 인코딩의 조합

  • 콘텐츠 인코딩과 전송인코딩은 동시에 사용될 수 있다.

전송 인코딩 규칙

  • 전송 인코딩 집합은 반드시 chunked를 포함해야 한다.
  • 청크 전송 인코딩이 사용되었다면, 메세지 본문에 적용된 마지막 전송 인코딩이 존재해야 한다.
  • 청크 전송 인코딩은 반드시 메세지 본문에 한 번 이상 적용되어야 한다.

이미지 청크 인코딩 예시



참고자료

📚