엔터티와 인코딩

ILLION·2024년 2월 18일
0

HTTP

목록 보기
13/18

1. HTTP 메시지

HTTP 메시지를 인터넷 운송 시스템의 컨테이너라고 비유한다면 HTTP 엔터티는 메시지의 실질적인 화물이라고 볼 수 있다.

메시지 엔터티는 엔터티 헤더와 엔터티 본문으로 이루어진다.

1.1 엔터티 헤더 필드

  • Content-Type
    • 엔터티에 의해 전달된 객체의 종류
  • Content-Length
    • 전달되는 메시지의 길이나 크기
  • Content-Language
    • 전달되는 객체와 가장 잘 대응되는 자연어
  • Content-Encoding
    • 객체 데이터에 대해 행해진 변형(압축 등)
  • Content-Location
    • 요청 시점을 기준으로 객체의 또 다른 위치
  • Content-Range
    • 만약 해당 엔터티가 부분 엔터티라면, 이 헤더는 이 엔터티가 전체에서 어느 부분의 해당하는지 정의
  • Content-MD5
    • 엔터티 본문의 콘텐츠에 대한 체크섬
  • Last-Modified
    • 서버에서콘텐츠가 생성 혹은 수정된 날
  • Expires
    • 엔터티 데이터가 더 이상 신선하지 않은 것으로 간주되기 시작하는 날짜와 시각
  • Allow
    • 해당 리소스에 대해 어떤 요청 메서드가 허용되는지
  • Etag
    • 인스턴스에 대한 고유 검사기
  • Cashe-Control
    • 문서가 캐시될 수 있는지에 대한 지시자

1.2 엔터티 본문

엔터티 본문은 가공되지 않은 데이터만을 담고 있다. 다른 정보들은 모두 헤더에 담겨 있다. 엔터티 본문은 가공되지 않은 날 데이터에 불과하기 때문에 Content-Type이나 Content-Encoding등 엔터티 헤더로 그 데이터의 의미에 대해 설명할 필요가 있다. 엔터티 본문은 또한 헤더 필드의 끝을 의미하는 빈 CRLF 줄 바로 다음부터 시작한다.

1.3 Content-Length: 엔터티의 길이

Content-Length 헤더는 메시지의 엔터티 본문의 크기를 바이트 단위로 나타낸다. 어떻게 인코딩 되었든 상관없이 크기를 표현할 수 있다.

Content-Length 헤더는 메시지를 청크 인코딩으로 전송하지 않는 이상 엔터티 본문을 포함한 메시지에서는 필수적으로 있어야 한다. Content-Length는 서버 충돌로 인해 메시지가 잘렸는지 감지하고자 할 때와 지속 커넥션을 공유하는 메시지를 올바르게 분할하고자 할 때 필요하다.

1.3.1 잘림 검출

옛날 버전의 HTTP는 커넥션이 닫힌 것을 보고 메시지가 끝났음을 인지했다. 그러나 Content-Length가 없다면 클라이언트는 커넥션이 정상적으로 닫힌 것인지 메시지 전송 중에 서버에 충돌이 발생한 것인지 구분하지 못한다. 클라이언트는 메시지 잘림을 검출하기 위해 Content-Length가 필요하다.

메시지 잘림은 캐싱 프록시 서버에서 특히 취약한데 만약 캐시가 잘린 메시지를 수신했으나 잘렸다는 것을 인식하지 못했다면, 캐시는 결함이 있는 콘텐츠를 저장하고 그 내용을 제공하게 될 것이다. 잘린 메시지를 캐시하는 위험을 줄이기 위해 캐싱 프록시 서버는 명시적으로 Content-Length 헤더를 갖고 있지 않은 HTTP 본문을 보통 캐싱하지 않는다.

1.3.2 Content-Length와 지속 커넥션

Content-Length 헤더는 지속 커넥션을 위해 필수다. 만약 응답이 지속 커넥션을 통해서 온 것이라면, 또 다른 HTTP 응답이 그 뒤를 이을 것이다. Content-Length 헤더는 클라이언트에게 메시지 하나가 어디서 끝나고 다음 시작은 어디인지 알려준다.

Content-Length헤더 없는 지속 커넥션을 만날 수 있는 상황이 있는데 바로 청크 인코딩을 사용할 때다. 청크 인코딩은 데이터를 각각 특정한 크기를 갖는 일련의 청크들로 쪼개어 보낸다. 만약 서버가 헤더가 생성되는 시점에서 엔터티 전체의 크기를 알 수 없다하더라도 서버는 청크 인코딩을 통해 엔터티를 잘 정의된 크기의 조각들도 전송할 수 있다.

1.3.3 콘텐츠 인코딩

HTTP는 보안을 강화하거나 압축하기 위해 본문을 인코딩하는데, 콘텐츠가 인코딩되어 있다면 Content-Length는 인코딩된 본문의 길이를 바이트 단위로 정의한다.

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

  1. 본문을 갖는 것이 허용되지 않는 특정 타입의 HTTP 메시지에서는, 본문 계산을 위한 Content-Length 헤더가 무시된다. 이 경우 Content-Length 헤더는 부가정보에 불가하며, 실제 본문 길이를 서술하지 않는다.(ex. post patch 메소드,(204코드))
  2. 메시지가 Transfer-Encoding 헤더를 포함하고 있다면, 메시지가 커넥션이 닫혀서 먼저 끝나지 않는 이상 엔터티는 '0바이트 청크'라 불리는 특별한 패턴으로 끝나야 한다.
  3. 메시지가 Content-Length 헤더를 갖는다면(그리고 메시지 유형이 엔터티 본문을 허용한다면), Transfer-Encoding 헤더가 존재하지 않는 이상 Content-Length 값은 본문의 길이를 담게 된다. 만약 Transfer-Encoding 헤더 필드가 있다면 Content-Length 헤더는 무시해야 한다.
  4. 메시지가 'multipart/byteranges' 미디어 타입을 사용하고 엔터티 길이가 별도로 정의되지 않았다면(Content-Length 헤더로), 멀티파트 메시지의 각 부분은 각자 스스로의 크기를 정의할 것이다.

2. 엔터티 요약

HTTP가 일반적으로 TCP/IP와 같이 신뢰할 만한 전송 프로토콜 위에서 구현됨에도 불구하고 불완전한 트랜스코딩 프록시나 버그 많은 중개자 프록시를 비롯한 여러가지 이유로 메시지의 일부분이 전송 중에 변형되는 일이 일어난다.

데이터 변경을 감지하지 위해 최초 엔터티가 생성될 때 송신자는 데이터에 대한 체크섬을 생성할 수 있으며 수신자는 모든 의도하지 않은 엔터티의 변경을 잡아내기 위해 그 체크섬으로 기본적인 검사를 할 수 있다.
체크섬으로서의 검사방법은 메시지 본문과 요약 헤더 모두를 교체하는 악의적인 공격에는 먼역력이 없다. 단지 의도하지 않은 변경을 감지하기 위한 것이다.

Content-MD5 헤더는 서버가 엔터티 본문에 MD5 알고리즘을 적용한 결과를 보내기 위해 사용된다. 오직 응답은 처음 만든 서버만이 계산해서 보낼 것이다. 중간에 있는 프록시와 캐시는 그 헤더를 변경하거나 추가하지 않을것이다.

3. 미디어 타입과 차셋(Charset)

Content-Type 헤더 필드는 엔터티 본문의 MIME 타입을 기술한다.

Content-Type의 값은 인터넷 할당 번호 관리기관에 등록된 표준화된 MIME 타입이다. MIME 타입은 주 미디어 타입(텍스트, 이미지, 오디오 등)으로 시작해서 뒤이어 빗금(/), 그리고 미디어 타입을 더 구체적으로 서술하는 부 타입으로 구성된다.

미디어 타입설명
text/htmlHTML 문서
text/plain플레인 텍스트 문서
image/gifGIF 이미지
image/jpegJPEG 이미지
audio/x-wavWAV 음향 데이터를 포함
model/vrml삼차원 VRML 모델
application/vnd.ms-powerpoint마이크로소프트 파워포인트 프레젠테이션
mulipart/byteranges여러 부분으로 나뉘는데, 각 부분은 전체 문서의 특정 범위를 담고 있다.
message/http완전한 HTTP 메시지

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

Content-Type 헤더는 내용 유형을 더 자세히 지정하기 위한 선택적인 매개변수도 지원한다.

엔터티의 비트 집합을 텍스트 파일의 글자들로 변환하기 위한 'charset' 매개변수가 대표적인 예이다.

💡 Content-Type: text/html; charset=utf-8

3.2 멀티파트 미디어 타입

MIME '멀티파트' 이메일 메시지는 서로 붙어있는 여러 개의 메시지를 포함하며, 하나의 복합 메시지로 보내진다.

HTTP는 멀티파트 본문도 지원한다. 그러나 일반적으로는 폼을 채워서 제출할 때와 문서의 일부분을 실어 나르는 범위 응답을 할 때의 두 가지 경우에만 사용된다.

4. 콘텐츠 인코딩

HTTP 애플리케이션은 콘텐츠를 보내기 전에 인코딩 할 수 있다.

큰 HTML 문서를 전송하기 전 압축하거나 콘텐츠를 암호화하여 보낸다.

4.1 콘텐츠 인코딩 과정

웹 서버가 원본 Content-Type과 Content-Length 헤더를 수반한 원본 응답 메시지를 생성한다.

콘텐츠 인코딩 서버(원 서버 또는 다운스트림 프락시)가 인코딩 된 메시지를 생성한다. 인코딩 된 메시지는 Content-Type은 같지만 Content-Length는 다르다. 콘텐츠 인코딩 서버는 Content-Encoding 헤더를 인코딩 된 메시지에 추가하여 수신 측 애플리케이션이 디코딩 할 수 있도록 도와준다.

수신 측 애플리케이션은 인코딩 된 메시지를 받아서 디코딩 후 원본을 얻는다.

💡 Content-Encoding: gzip

Gzip 콘텐츠 인코더를 통해 인코딩 된 원본을 Gzip 콘텐츠 디코더를 통해 디코딩 하여 원본을 얻는다.

4.2 콘텐츠 인코딩 유형

HTTP는 몇 가지 표준 콘텐츠 인코딩 유형을 정의하고 확장 인코딩으로 인코딩을 추가하는 것도 허용한다.

Content-Encoding 헤더는 표준화된 토큰 값을 이용해서, 인코딩에 사용된 알고리즘들에 대해 기술한다.

콘텐츠 인코딩 값설명
gzip엔터티에 GNU zip 인코딩이 적용되었음을 의미
compress엔터티에 대해 유닉스 파일 압축 프로그램인 'compress'가 실행었엇음을 의미
deflate엔터티가 zlib 포맷으로 압축되었음을 의미
identity엔터티에 어떤 인코딩도 수행되지 않았음을 의미 (Content-Encoding 헤더가 없을 경우 이 값)

gzip, compress, deflate 인코딩은 전송되는 메시지의 크기를 정보의 손실 없이 줄이기 위한 무손실 압축 알고리즘

gzip이 가장 효율적이고 많이 사용됨

4.3 Accept-Encoding 헤더

서버에서 클라이언트가 지원하지 않는 인코딩을 사용하는 것을 막기 위해, 클라이언트는 자신이 지원하는 인코딩 목록을 Accept-Encoding 요청 헤더를 통해 전달한다.

Accept-Encoding 헤더를 전달하지 않는다면 서버는 클라이언트가 어떤 인코딩이든 받아들일 수 있다고 간주한다. (= Accept-Encoding: *)

💡 Accept-Encoding 헤더의 몇 가지 예
  • Accept-Encoding: compress, gzip
  • Accept-Encoding:
  • Accept-Encoding: *
  • Accept-Encoding: compress;q=0.5, gzip;q=1.0
  • Accept-Encoding: gzip;q=1.0, identity;q=0.5, *;q=0

클라이언트는 각 인코딩에 Q(quality) 값을 매개변수로 더해 선호도를 나타낼 수 있다. (min: 0.0 ~ max:1.0)

5. 전송 인코딩과 청크 인코딩

콘텐츠 인코딩된 메시지는 단지 메시지의 엔터티 부분만 인코딩한다. 전송 인코딩된 메시지에서는 인코딩은 전체 메시지에 대해 적용되어 메시지 자체의 구조를 바꾼다.

SSL과 같은 유명한 전송 계층 보안 방식이 있기 때문에 전송 인코딩 보안은 흔하지 않다.

5.1 Tranfer-Encoding 헤더

전송 인코딩을 제어하고 서술하기 위해 정의된 헤더 두 가지
HTTP/1.1 버전에서는 정의되어 있으나, 현재 표준인 HTTP/3.0에는 정의되어 있지 않으며 Tranfer-Encoding헤더를 사용해서는 안된다고 한다.

  • Transfer-Encoding : 안전한 전송을 위해 어떤 인코딩이 메시지에 적용되었는지 수신자에게 알려준다.
  • TE : 어떤 확장된 전송 인코딩을 사용할 수 있는지 서버에게 알려주기 위해 요청 헤더에 사용됨
    Accept-Transfer-Encoding과 같은 의미이다.

5.2 청크 인코딩

청크 인코딩은 메시지를 일정 크기의 청크 여럿으로 쪼갠다. 서버는 각 청크를 순차적으로 보낸다.

청크 인코딩을 이용하면 메시지를 보내기 전에 전체 크기를 알 필요가 없어진다.

청크 인코딩이 전송 인코딩의 한 형태이며 본문이 아닌 메시지의 속성임에 주목해야 한다.

5.3.1 청크와 지속 커넥션

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

콘텐츠가 서버에서 동적으로 생성되는 경우에는, 보내기 전에 본문의 길이를 알아내는 것이 불가능할 것이다.

청크 인코딩은 서버가 본문을 여러 청크로 쪼개 보낼 수 있게 해줌으로써 이것에 대한 해법을 제공한다.

동적으로 본문이 생성되면서, 서버는 그중 일부를 버퍼에 담은 뒤 그 한 덩어리를 그의 크기와 함께 보낼 수 있다.

마지막 청크는 본문의 끝을 의미하기 때문에 크기가 0이다.

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

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

콘텐츠 인코딩을 사용해서 HTML 파일을 압축하고 그 청크 데이터를 전송 인코딩을 사용해서 전송

5.3.3 전송 인코딩 규칙

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

6. 시간에 따라 바뀌는 인스턴스

같은 URL의 리소스에 대해 시간에 따라 다른 인스턴스(객체)를 응답 받을 수 있다.

대표적인 두 가지는 범위 요청과 델타 인코딩이다. 이 둘 모두 클라이언트가 자신이 갖고 있는 리소스의 사본이 서버가 갖고 있는 것과 정확히 같은지 판단하고 상황에 따라 새 인스턴스를 요청할 수 있다.

6.1 검사기와 신선도

클라이언트가 서버로부터 처음 받은 리소스를 캐시에 저장하는데, 만료되면 서버에게 최신 사본을 요구하고 서버는 둘을 비교 한 후 변경되었으면 새로 응답

6.1.2 신선도

서버는 Expires와 Cache-Control 헤더를 통해 얼마나 콘텐츠를 캐시하고 있었는지, 그것이 신선하다고 할 수 있는지 정보를 제공한다.

6.1.3 조건부 요청과 검사기

  • 클라이언트가 같은 리소스에 한 번 이상 접근했을 때, 우선 현재 사본이 여전히 신선한지 판별
  • 만약 그렇지 않다면, 클라이언트는 반드시 서버로부터 최신 버전을 얻어 와야 함
  • 리소스가 변경되지 않은 상황에서 똑같은 사본을 다시 받아오는 상황을 피하기 위해, 클라이언트는 서버에 현재 사본을 유일하게 식별할 수 있는 검사기를 명시해서 조건부 요청을 보낼 수 있음
  • 서버는 오직 클라이언트의 사본과 다를 때만 리소스의 사본을 보낼 것이다.

조건부 요청을 If 로 시작하는 조건부 헤더에 의해 구현된다. 각 조건부 요청은 특정 검사기 위에서 동작한다.

요청 유형검사기설명
If-Modified-SinceLast-Modified지난번 Last-Modified 응답 헤더에 들어있었던 시각에 마지막으로 수정된 버전이 더 이상 최신 버전이 아니라면, 그 리소스의 사본을 보내라
If-Unmodified-SinceLast-Modified지난번 Last-Modified 응답 헤더에 들어있었던 시각에 마지막으로 수정된 버전에서 변환 것이 없다면, 그 리소스의 사본을 보내라
If-MatchETag지난번 ETag 응답 헤더에 들어있었던 것과 엔터티 태그가 같다면, 그 리소스의 사본을 보내라
If-None-MatchETag지난번 ETag 응답 헤더에 들어있었던 것과 엔터티 태그가 다르다면, 그 리소스의 사본을 보내라

요약하면 클라이언트가 같은 리소스에 한 번 이상 접근했을 때 우선 현재 사본이 여전히 신선한지 판별한다. 많은 그렇지 않으면 클라이언트는 반드시 서버로부터 최신 버전을 얻어 와야 한다. 리소스가 변경되지 않은 상황에서 똑같은 사본을 다시 받아오는 상황을 피하기 위해 클라이언트는 서버에 현재 사본을 유일하게 식별할 수 있는 검사기를 명시해서 조건부 요청을 보낼 수 있다. 서버는 오직 클라이언트 사본과 다를 때만 리소스의 사본을 보낼 것이다.

7. 범위 요청

클라이언트가 문서의 일부분이나 특정 범위만 요청할 수 있도록 해준다. 범위 요청을 이용하면 HTTP 클라이언트는 받다가 실패한 엔터티를 일부 혹은 범위로 요청함으로써 다운로드를 중단된 시점에서 재개할 수 있다.

모든 서버가 범위 요청을 받아들일 수 있는 것은 아니지만 많은 경우 가능하다. 서버는 클라이언트에게 자신이 범위를 받아들일 수 있는지 응답에 Accept-Range헤더를 포함시키는 방법으로 알려줄 수 있다.

8. 델타 인코딩

델타 인코딩은 객체 전체가 아닌 변경된 부분에 대해서만 통신하여 전송량을 최적화하는 HTTP 프로토콜의 확장이다. 만료된 웹 페이지에 대해 새 페이지 전체를 보내는 대신 변경된 부분만 서버가 보낸다면 클라이언트는더 빨리 페이지를 얻을 수 있다.

profile
결과를 중요시하기보단 과정을 중요하게 생각하는 마음가짐

0개의 댓글