Development/Common

http - Content Length와 Transfer Encoding

linuxism 2012. 7. 18. 13:25




제  목 : HTTP 1.1의 Content Length와 Transfer Encoding
작성자 : 좋은진호(truefeel, http://coffeenix.net/ )
작성일 : 2005.12.2~3(금~토)

HTTP 1.1 에서는 커넥션이 끊어지지 않고 유지되는 Keep Alive connection(persistent connection)
을 지원한다. apache 에서 httpd.conf 에 Keepalive on으로 설정하면 Keep alive connection을 지원
하게 된다.

웹페이지를 가져오는 프로그램을 만들 때(php에서 fsockopen을 사용하는 경우도)를 생각해보자.
하나의 커넥션이 계속 유지된 상태라면 정확한 본문의 내용이 어디까지인지, 그리고 길이는 얼마인지
어떻게 확인해야할까? 또한 connection close형태로 요청을 하더라도 HTTP 1.1에서는 본문내용을
chunked enconig(이게 뭔지는 글 중간에 설명한다.) 형식으로 표시하는 경우도 있다.
이런 것처럼 HTTP 1.1로 요청을 할 때는 Content Length헤더로 표시되는 경우와 chunked encoding
을 사용하는 경우 등 2가지 response 형식을 잘 구분해서 처리해주어야 한다.

1. Content Length 헤더를 보여주는 경우

 
telnet coffeenix.net 80
Trying 211.xxx.xxx.xx...
Connected to coffeenix.net (211.xxx.xxx.xx).
Escape character is '^]'.
GET /truefeel/files/mail_log.pl.txt HTTP/1.1      <-- HTTP/1.1 형태로 요청
Host: coffeenix.net
Connection: close
                                 <-- 요청 후 접속을 바로 끊음

HTTP/1.1 200 OK                                   <-- 여기 부터는 서버의 응답
Date: Sat, 03 Dec 2005 15:10:17 GMT               <-- RFC 1123을 따르는 날짜 표시
Server: Secured                                   <-- 웹서버명 ^^
Last-Modified: Sun, 18 Jan 2004 20:26:49 GMT
ETag: "64151-7dc-400aec09"
Accept-Ranges: bytes
Content-Length: 2012                              <-- contents의 길이. 2012bytes
Connection: close
Content-Type: text/plain

#!/usr/bin/perl                                   <-- 여기 부터는 contents
#
# procmail을 통해 넘겨온 메일 수신 정보를 DB로.
#
... 생략 ...
Connection closed by foreign host.
 


한가지 더 보자. 아래와 같이 요청하면 connection은 계속 유지된 상태로 있게 된다.

 
telnet www.cyworld.nate.com 80
Trying 211.115.11.30...
Connected to www.cyworld.nate.com (211.115.11.30).
Escape character is '^]'.
GET /main2/index.htm HTTP/1.1                     <-- HTTP/1.1 형태로 요청
Host: www.cyworld.nate.com


HTTP/1.1 200 OK                                   <-- 여기 부터는 서버의 응답
Cache-Control: max-age=31536000
Content-Length: 162368                            <-- contents의 길이. 162368bytes
Content-Type: text/html
Last-Modified: Sat, 03 Dec 2005 14:58:50 GMT
Accept-Ranges: bytes
ETag: "fee1c0111af8c51:d63"
Server: Microsoft-IIS/6.0
Date: Sat, 03 Dec 2005 15:24:06 GMT
 


위처럼 'Content-Length' 헤더가 있다면 body부분에서 해당 길이만큼만 받아오고, close하면 된다.


2. Transfer Encoding 헤더 (Chunked enconding 방식)

Chunked enconding은 php나 CGI등에서 주로 사용하며, 헤더에는 Transfer-Encoding: chunked가
표시되고, 본문은 chunk size+내용+chunk size+내용... 형식으로 표시된다.

 
telnet coffeenix.net 80
Trying 211.xxx.xxx.xx...
Connected to coffeenix.net (211.xxx.xxx.xx).
Escape character is '^]'.
GET / HTTP/1.1                                    <-- HTTP/1.1 형태로 요청
Host: coffeenix.net


HTTP/1.1 200 OK                                   <-- 여기 부터는 서버의 응답
Date: Sat, 03 Dec 2005 16:29:25 GMT
Server: Secured
Transfer-Encoding: chunked                        <-- chunked encoding
Content-Type: text/html

e22                         <-- chunked 된 size. 16진수로 표시되며, bytes 단위
... 내용 ...                <-- 해당 e22(3618 bytes) 길이의 contents
192                         <-- 16진수 192
... 내용 ...                <-- 192(402 bytes) 길이의 contents
f76
... 내용 ...
101
... 이하 생략 ..
0                           <-- 끝을 표시한다
 


보다 정확하게 보자면 chunk size+CRLF문자(CRLF는 ASCII코드 16진수로 0d0a)가 표시되고,
내용+CRLF문자가 오는 형태가 반복되며 0+CRLF문자로 마무리를 한다.
따라서 웹페이지 읽어올 때는 처음 chunk size를 알아낸 후 해당 길이만큼 내용을 분리하고
다시 chunk size을 확인, 내용 분리하는 과정을 반복한 후 내용만 합치는 과정이 필요하다.

3. php에서 Content-Length 헤더 사용

윈도의 응용프로그램과 php로 된 웹페이지간의 통신이 필요한 경우 chunked encoding된 페이지
보다는 Content-Length 헤더를 따르도록 하면 응용 프로그램쪽 개발이 보다 쉬워질 것이다.

이처럼 필요한 페이지만 Content-Length 헤더가 표시하고 싶다면 php에서 출력 버퍼링을 사용하도록
하면 된다. php 시작에 ob_start()를 넣고 마지막에 ob_end_flush()를 사용하면 그 사이에 출력되는
모든 내용을 버퍼에 쌓아 둔 후 마지막에 출력을 하게 된다.
물론 버퍼에 저장된 내용 길이를 파악한 후 Content-Length: 헤더를 뿌려주는 것도 잊지 말자.

 
< ?
ob_start();

... 프로그램 코드 ...
... HTML ... 

$length=ob_get_length();
header("Content-Length: $length");
ob_end_flush();
?>
 



4. 참고 자료

* Content Length & Transfer Encoding
  http://www.simtec.ltd.uk/httpgallery/chunked/

* HTTP/1.1표준(안) (김용운 역)
  http://coffeenix.net/doc/network/http11.txt

* php ob_start() function
  http://kr.php.net/manual/kr/function.ob-start.php


출처 - http://coffeenix.net/board_print.php?bd_code=1280