15장 엔터티와 인코딩

메시지는 컨테이너, 엔터티는 화물

  • HTTP 메시지를 인터넷 운송 시스템의 컨테이너라고 생각한다면, HTTP 엔터티는 메시지의 실질적인 화물이다.
HTTP/1.0 200 OK
Server: Netscape-Enterprise/3.6
Date: Tue, 15 Nov 1994 08:12:31 GMT
Content-Type: text/plain
Content-Length: 18

Hi! I'm a message!
  • 위에서 Content-Type, Content-Length는 엔터티 헤더
  • Hi! I'm a message!는 엔터티 본문
  • 주요 엔터티 헤더
    • Content-Type: 엔터티 본문의 미디어 타입
    • Content-Length: 엔터티 본문의 길이
    • Content-Language: 엔터티 본문의 자연 언어
    • Content-Encoding: 엔터티 본문의 압축 방식
    • Content-Location: 엔터티 본문의 베이스 URL
    • Content-Range: 엔터티 본문의 범위
    • Content-MD5: 엔터티 본문의 체크섬
    • Last-Modified: 엔터티 본문의 최종 수정 시간
    • Expires: 엔터티 본문의 만료 시간
    • Allow: 허용되는 요청 메서드
    • ETag: 엔터티 태그, 엄밀하게는 엔터티 헤더로 정의되지 않는다.
    • Cache-Control: 캐시 지시자, 엄밀하게는 엔터티 헤더로 정의되지 않는다.

엔터티 본문

  • 엔터티 본문은 가공되지 않은 데이터만을 담고 있다. 가공되지 않은 데이터기 때문에 엔터티 헤더가 데이터의 의미에 대해 설명해야한다.
  • 엔터티 본문은 헤더 필드의 끝을 의미하는 빈 CRLF 줄 바로 다음부터 시작한다.
  • HTTP 메시지의 실례(텍스트 vs 이미지)

http15-1.jpeg

Content-Length: 엔터티의 길이

  • 메시지의 엔터티 본문 크기를 바이트 단위로 나타낸다.
  • 인코딩 방식과 상관없이 크기를 표현 가능하다. (gzip으로 압축된 텍스트 파일은 원래크기가 아닌 압축된 후의 크기이다.)

잘림 검출

  • 예전에는 HTTP 커넥션이 닫힌 것을 보고 메시지가 끝났음을 인지했으나 지속 커넥션을 사용하면서 잘림 검출이 필요하게 되었다.
  • Content-Length를 통해 커넥션이 정상적으로 닫힌 것인지 잘림이 발생한 것인지 판단할 수 있다.
  • 특히 메시지 잘림은 캐싱 프락시 서버에서 문제가 발생할 수 있다.(잘린 메시지를 캐시하면 위험하다.)

잘못된 Content-Length

  • Content-Length가 잘못된 값을 담고 있는 경우 아예 빠진 것보다 더 큰 피해를 유발할 수 있다.

Content-Length와 지속 커넥션(Persistent Connection)

  • Content-Length는 지속 커넥션에서 매우 중요하다. 커넥션이 닫히지 않고 계속해서 사용되기 때문에 메시지 하나가 끝나는 시점을 알아야한다.
  • Content-Length 헤더가 없는 지속 커넥션을 만날 수 있는 상황이 있는데 청크 인코딩을 사용할 때이다. (이후에서 자세히 설명함)

콘텐츠 인코딩

  • HTTP는 엔터티 본문을 인코딩할 수 있다. 인코딩 된 경우 Content-Length는 인코딩된 본문의 길이를 바이트 단위로 나타낸다.

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

엔터티 본문의 길이와 끝나는 위치를 바르게 판별하는 상황별 규칙

  1. 본문을 갖는 것이 허용되지 않는 특정 타입의 HTTP 메시지에서는 Content-Length 헤더가 무시된다.
    • 대표적 예시는 HEAD 메서드의 응답이다. HEAD 메서드는 GET과 동일한 응답을 반환하지만 본문을 포함하지 않는다.
    • 1XX, 204, 304 응답은 정보성 Content-Length 헤더를 갖지만 본문을 포함하지 않는다.
  2. 메시지가 Transfer-Encoding 헤더를 갖는 경우, 메시지가 커넥션이 닫혀서 먼저 끝나지 않는 이상 엔터티는 0 바이트 청크라 불리는 특별한 패턴으로 끝나야한다.
  3. 메시지가 Content-Length 헤더를 갖는다면, Transfer-Encoding 헤더가 존재하지 않는 이상 Content-Length 값은 본문의 길이를 담는다. Transfer-Encoding 헤더가 존재한다면 Content-Length는 무시된다.
  4. 메시지가 multipart/byteranges 미디어 타입을 사용하고, Content-Length 헤더가 없으면 멀티파트 메시지의 각 부분은 스스로 크기를 정의할 것이다. 멀티파트는 자신의 크기를 스스로 결정할 수 있는 유일한 엔터티 본문유형이다.
  5. 위의 규칙 어디에도 해당되지 않으면 엔터티는 커넥션이 닫힐 때 끝난다. 이 경우 서버만이 커넥션을 닫을 수 있다. 클라이언트는 커넥션을 닫을 수 없다.
  6. HTTP/1.1명세는 본문은 있지만 Content-Length 헤가가 없는 경우, 메시지의 길이를 판별할 수 없으면 400 Bad Request를 반환하라고 규정한다. 하지만 이 규칙은 HTTP/1.1이 처음 나왔을 때부터 존재했지만, 실제로는 적용되지 않았다. 그래서 HTTP/1.1이 나온지 10년이 지난 2001년에 RFC 2616이 나왔다. 이 RFC에서는 Content-Length가 없는 경우, 메시지의 길이를 판별할 수 없으면 411 Length Required를 반환하라고 규정했다. 하지만 이 규칙도 실제로는 적용되지 않았다. 그래서 2014년에 RFC 7230이 나왔다. 이 RFC에서는 Content-Length가 없는 경우, 메시지의 길이를 판별할 수 없으면 400 Bad Request를 반환하라고 규정했다. 이 규칙은 실제로 적용되고 있다.

엔터티 요약

  • 메시지의 일부분이 전송 중에 변형되는 일이 일어나는 경우 엔터티 요약을 사용할 수 있다.
  • 엔터티 요약은 엔터티 본문의 체크섬이다. 엔터티 요약은 엔터티 본문의 체크섬을 계산하고, 엔터티 요약 헤더에 체크섬을 담아서 보낸다. 수신자는 엔터티 본문을 받고 체크섬을 계산한 후 엔터티 요약 헤더의 체크섬과 비교한다. 만약 일치하지 않으면 엔터티 본문이 변형된 것이다.
  • Content-MD5헤더는 엔터티 요약을 위해 사용되는 유일한 표준 헤더이다. 하지만 Content-MD5는 보안에 취약하다. 그래서 Content-MD5는 HTTP/1.1에서 폐기되었다. 대신에 Digest 헤더를 사용할 수 있다. Digest 헤더는 Content-MD5보다 보안이 강화되었지만, 아직까지는 널리 사용되지 않는다.

미디어 타입과 차셋(Charset)

  • Content-Type 헤더는 엔터티 본문의 미디어 타입을 나타낸다. 미디어 타입은 MIME 타입이라고도 불린다. MIME 타입은 메시지의 본문이 어떤 종류의 데이터인지를 나타낸다. 예를 들어, 텍스트인지, HTML인지, GIF인지, JPEG인지 등을 나타낸다.
미디어 타입 설명
text/plain 텍스트 문서
text/html HTML 문서
image/jpeg JPEG 이미지
image/gif GIF 이미지
aduio/x-wav WAV 오디오
model/vrml VRML 모델
application/vnd.ms-powerpoint 파워포인트 문서
multipart/byteranges 멀티파트 문서
message/http HTTP 메시지(ex. TRACE)

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

  • Content-Type 헤더는 내용 유형을 더 자세히 지정하기 위한 선택적 매개 변수도 지원한다.
  • 대표적인 예시는 charset이다. charset은 텍스트 매체를 위한 문자 인코딩을 지정한다. 텍스트 매체는 텍스트 파일이나 HTML 문서 등을 말한다. charset은 텍스트 매체의 문자 인코딩을 지정한다. 예를 들어, UTF-8, EUC-KR, ISO-8859-1 등이 있다.
Content-Type: text/html; charset=utf-8

멀티파트 미디어 타입

  • MIME ‘멀티파트’ 이메일 메시지는 서로 붙어있는 여러 개의 메시지를 포함하며, 하나의 복합 메시지로 보내진다.
  • 문자열 하나로 서로의 결계를 식별한다.
  • HTTP는 멀티파트 본문도 지원하는데 폼으로 채워서 제출할 때와 문서의 일부분을 실어 나르는 범위 응답을 할 때의 두 가지 경우에만 사용된다.

멀티파트 폼 제출

  • HTTP 폼을 채워서 제출하면, 가변 길이 텍스트 필드와 업로드 될 객체는 멀티파트 본문에 담겨서 서버로 전송된다.
  • HTTP는 멀티파트 폼 제출을 위해 multipart/form-data 또는 multipart/mixed 미디어 타입을 정의했다.
Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6
  • boundary는 본문의 서로 다른 부분을 구분하기 위한 구분자로 쓰인다.
<FORM method="POST" enctype="multipart/form-data" action="http://server.com/cgi/handle">
  <P>
    What is your name?
    <INPUT type="text" name="submit-name"><BR>
    What files are you sending?
    <INPUT type="file" name="files"><BR>
    <INPUT type="submit" value="Send">
    <INPUT type="reset">
  </P>
</FORM>

사용자가 text에 Sally을 입력하고, 파일을 essayfile.txt를 선택하고, Send 버튼을 누르면 아래와 같은 HTTP 요청이 생성된다.

Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Sally
--AaB03x
Content-Disposition: form-data; name="files"; filename="essayfile.txt"
Content-Type: text/plain
...contents of essayfile.txt...
--AaB03x--

만약 두번째 파일로 imagefile.gif를 선택했다면 아래와 같은 HTTP 요청이 생성된다.

Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Sally
--AaB03x
Content-Disposition: form-data; name="files";
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="essayfile.txt"
Content-Type: text/plain
...contents of essayfile.txt...
--BbC04y
Content-Disposition: file; filename="imagefile.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of imagefile.gif...
--BbC04y--
--AaB03x--

멀티파트 범위 응답

  • 범위 요청에 대한 HTTP 응답 또한 멀티파트가 될 수 있다.
  • 멀티파트 범위 응답은 Content-Type:multipart/byteranges 미디어 타입을 사용한다.

콘텐츠 인코딩

  • 콘텐츠를 보내기 전에 인코딩을 하는 경우도 있다.
  • 발송하는 쪽에서 콘텐츠에 적용한다.

콘텐츠 인코딩 과정

  1. 웹 서버가 원본 Content-Type과 Content-Length 헤더를 수반한 원본 응답 메시지를 생성한다.
  2. 콘텐츠 인코딩 서버가 인코딩된 메시지를 생성한다. Content-Type은 같지만 Content-Length는 다르다. Content-Encoding 헤더를 추가한다.
  3. 수신 측 프로그램은 인코딩된 메시지를 받아서 디코딩하고 원본 메시지를 얻는다.

콘텐츠 인코딩 유형

  • 인코딩은 각 콘텐츠 인코딩 알고리즘에 고유한 토큰을 할당하는 IANA를 통해 표준화된다.
  • Content-Encoding 헤더는 표준화된 토큰값을 이용해서, 인코딩에 사용된 알고리즘에 대해 기술한다.
  • 인코딩 토큰 예시
인코딩 토큰 설명
gzip gzip 압축
compress UNIX compress 압축
deflate zlib deflate 압축
identity 인코딩 없음

Accept-Encoding 헤더

  • 서버에서 클라이언트가 지원하지 않는 인코딩을 사용하는 것을 막기 위해, 클라이언트는 자신이 지원하는 인코딩 목록을 Accept-Encoding 헤더에 담아서 보낸다.
Accept-Encoding: gzip, compress
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
  • Accept-Encoding필드는 지원되는 인코딩들을 쉼표로 구분된 목록을 담고 있다.
  • Q값은 매개변수로 선호도를 나타낸다. 가장 원치 않음은 0.0 가장 선호함은 1.0 이다.
  • *는 모든 인코딩을 의미한다.

전송 인코딩과 청크 인코딩

이전 절에서는 메시지 본문에 적용된 가역적 변환인 콘텐츠 인코딩에 대해 논의 했다.
콘텐츠 인코딩은 콘텐츠 포맷과 긴밀하게 연관되어 있다. 텍스트 파일은 흔히 gzip으로 압축하지만 JPEG 이미지는 압축하지 않는다.
이러한 경우 전송 인코딩을 사용할 수 있다. 전송 인코딩은 메시지 본문에 적용되는 것이 아니라 메시지 전체에 적용되어 메시지 자체의 구조를 바꾼다.

안전한 전송

  • HTTP에서 전송된 메시지의 본문이 문제를 일으킬 수 있는 이유

    알 수 없는 크기

  • 몇몇 게이트웨이 애플리케이션과 콘텐츠 인코더는 메시지의 길이를 알 수 없다. 이런 경우에는 메시지의 끝을 알리는 방법이 필요하다.

    보안

  • 공용 전송 네트워크로 메시지 콘텐츠를 보내기 전에 전송 인코딩을 사용해 알아보기 어렵게 뒤섞어버리는 방법도 있다. 이미 SSL과 같은 유명한 전송 계층 보안 방식이 있기 때문에 전송 인코딩 보안은 흔하지 않다.

Transfer-Encoding 헤더

전송인코딩을 제어하고 서술하기 위해 정의된 헤더는 단 두개이다.

Transfer-Encoding

안전한 전송을 위해 어떤 인코딩이 메시지에 적용되었는지 수신자에게 알려준다.

TE

어떤 확장된 전송 인코딩을 사용할 수 있는지 서버에게 알려주기 위해 요청 헤더에 사용한다.

청크 인코딩

  • 청크 인코딩은 메시지를 일정 크기의 청크 여럿으로 쪼갠다.
  • 서버는 각 청크를 순차적으로 보낸다.
  • 청크 인코딩을 이용하면 메시지를 보내기 전에 전체 크기를 알 필요가 없어진다.
  • 본문이 동적으로 생성됨에 따라, 서버는 그중 일부를 버퍼에 담은 뒤 그 한 청크를 그것의 크기와 함께 보낼 수 있다.
  • 본문 전체를 모두 보낼 때까지 이단계를 반복한다.
  • 청크 인코딩은 메시지의 끝을 알리기 위해 마지막에 0바이트 크기의 청크를 보낸다.
  • 청크 인코딩이 전송 인코딩의 한 형태이다. 따라서 엔티티본문이 아닌 메시지 속성이다.

청크와 지속 커넥션

  • 청크 인코딩은 서버가 본문을 여러 청크로 쪼개 보낼 수 있게 해줌으로써 지속커넥션에서 본문의 크기를 몰라도 된다.
  • 동적으로 본문이 생성되면서, 서버는 그중 일부를 버퍼에 담은 뒤 그 한 청크를 그의 크기와 함께 보낼 수 있다. 본문 전체를 모두 보낼 때까지 이 단계를 반복한다.
  • 청크 인코딩은 메시지의 끝을 알리기 위해 마지막에 0바이트 크기의 청크를 보낸다.
  • 다음 응답을 위해 커넥션이 열린 채로 유지할 수 있다.

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

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

  • 전송 인코딩은 반드시 chunked 를 포함해야한다. 유일한 예외는 메시지가 커넥션의 종료로 끝나는 경우 뿐이다.
  • 청크 인코딩 사용시 메시지 본문에 적용된 마지막 인코딩이 존재해야한다.
  • 청크 전송인코딩은 반드시 본문에 한 번 이상 적용되어야한다.

전송 인코딩은 HTTP/1.1에서의 새로운 기능이므로, 비 HTTP/1.1에 전송 인코딩 메시지를 보내지 않도록 주의해야 한다.

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

  • 인스턴스 조작 : 클라리언트가 자신이 갖고 있는 리소스의 사본이 서버가 갖고 있는 것과 정확하게 같은지 판단하고, 상황에 따라 새 인스턴스를 요청할 수 있는 능력을 말한다.
  • 인스턴스 조작의 대표적인 두가지가 범위 요청과 델타 인코딩이다.

검사기와 신선도

  • 만료되면 새로운 사본을 요구하는 것
  • 조건부 요청은 검사기를 사용해 자신의 사본이 더 이상 유효하지 않을 때만 사본을 보내달라고 요청하는 것

신선도

  • 신선한지 여부를 알려줄 수 있는 헤더는 Expires와 Cache-Control이다.
  • Expires는 정확한 날짜, 클라이언트와 서버의 시계가 동기화되어 있어야 해서 쉽지는 않다.
  • Cache-Control는 상대시간을 이용. 서버가 떠난 후로부터의 시간을 초단위로 정한다. 시계 동기화에 의존하지 않아서 더 정확하다.

더 자세한 내용은 7장에서 다뤘다.

조건부 요청과 검사기

리소스가 바뀐 경우에만 사본을 요청한다. ‘If-‘로 시작하는 조건부 헤더에 의해 구현된다.

  • 약한 검사기: 인스턴스가 고유하게 식별되지 않는 검사기 (ex. 바이트 단위의 크기, 최종 변경 시각)
  • 강한 검사기: 인스턴스를 고유하게 식별하는 검사기 (ex. MD5 체크섬, ETag)

범위 요청

  • Range 헤더를 사용해 리소스의 일부분만 요청할 수 있다.
  • 서버로 부터 처음 일부의 바이트만 받고 실패했을 경우 이어서 받을 수 있도록 Range 헤더를 사용한다.
  • p2p와 같이 파일의 다른 부분을 여러 다른 피어로부터 동시에 다운로드 받을 때도 사용한다.
  • 서버는 Accept-Ranges 헤더를 사용해 범위 요청을 지원하는지 알려준다.

델타 인코딩

  • 델타 인코딩은 리소스의 일부분만 요청하는 것이 아니라, 리소스의 일부분만 보내는 것이다.
  • 일종의 인스턴스 조작으로 볼 수 있다.
  • 클라이언트가 어떤 버전을 가지고 있는지, 델타를 적용하기 위해 어떤 알고리즘을 알고 있는지를 말해준다.
  • 서버는 자신이 그 버전을 가지고 있는지, 그리고 어떻게 델타를 계산할 것인지를 확인한다.
  • 서버는 델타를 클라이언트에 보내주고, 최신 버전에 대한 새 식별자를 명시한다.
  • A-IM 헤더: 클라이언트의 요청헤더, 자신이 델타 응답을 받아들일 수 있음을 알림
  • IM 헤더: 서버의 응답헤더, 자신이 델타 응답을 보낼 수 있음을 알림. 응답 코드가 226 IM Used 이면 델타 응답을 보낼 수 있다.
  • Delta-Base 헤더: 서버의 응답헤더, 델타를 계산하기 위한 기준이 되는 ETag를 명시한다.

인스턴스 조작, 델타 생성기 그리고 델타 적용기

  • 델타 인코딩은 전송 시간을 줄일 수 있지만 구현하기가 까다로울 수 있다.
  • 서버가 이전 사본의 모든 버전을 유지하고 있어야하기에 디스크 공간을 더 늘려야 한다. 이로 인해 전송량 감소로 얻은 이득을 금방 무의미하게 만들 것이다.

results matching ""

    No results matching ""