HTTP Compression (II) - Principle
요번엔 HTTP 압축이란 것이 구체적으로 어케 작동하는가를 살펴보도록 하겠다. 이런거 다 때려치고 곧바로 HTTP 압축을 사이트에 적용해 보고자 하는 사람들에겐 마니 미안타... 원리를 모르고 뎀비는 것 처럼 용감한 것이 없다(XX 하면 용감하단 말을 이런 때 쓰는거 아뉠까?). 이런거 아무런 도움 안된다...
HTTP 1.1 Protocol
HTTP 1.1 프로토콜을 명세하고 있는 RFC2616을 찬찬히 살펴보면 복잡한 설명과 긴 내용에 한숨만 나올 것이다(물론 필자도 그렇다). HTTP 압축에 관련된 프로토콜 명세는 그다지 복잡하지도 많지도 않다. 간단히 꼭 필요한 거만 설명하겠다(사실 필자가 아는 것이 그것밖에 안되므로... -_-).
HTTP 압축은 (사실 HTTP 프로토콜은 HTTP 압축이란 용어를 사용하지 않는다. Content-Coding 이란 용어를 쓰며 이 Content-Coding이 주로 압축의 용도로 사용된다고 명시하고 있을 뿐이다) 두 개의 HTTP 헤더 필드에 의해 작동한다. Accept-Encoding 헤더와 Content-Encoding 헤더가 그것인데 이 두개의 HTTP 헤더 값을 통해 클라이언트(웹 브라우저)와 서버(웹 서버)가 압축을 할 것인가 말 것인가 그리고 압축에 사용되는 알고리즘을 쑈부치는 것이다.
Accept-Encoding은 클라이언트가 웹 서버에게 보내는 HTTP Request 메시지에 명세 하는 값으로서 클라이언트가 이 헤더에 명시된 인코딩(압축)을 이해하고 디코딩(압축 해제)을 수행할 수 있다는 것을 서버에 알리는데 사용한다. 즉, 클라이언트가 압축된 컨텐츠를 받아 압축을 해제할 수 있는 압축 알고리즘을 서버에 알리는 용도로 Accept-Encoding 헤더가 사용된다. IE 6.0에서 서버에 보내는 HTTP Request 메시지를 우리의 멋진 유틸리티인 Fiddler로 살짝 디비보면 Accept-Encoding이 다음과 같이 명시 되어 있음을 알 수 있다.
Accept-Encoding: gzip, deflate
요 헤더 값이 의미하는 것은 IE가 gzip 그리고 deflate 인코딩, 즉 압축 알고리즘을 이해하므로 웹 서버가 HTTP Response 메시지를 이들 알고리즘 중 하나로 압축해서 보내도 된다는 것을 서버에게 찔러 주는 것이다.
웹 서버는 Accept-Encoding의 값을 살펴보고 필요에 따라서 HTTP Response(HTML, CSS, 이미지 등의 결과물)를 압축 할 수 있다. 웹 서버가 HTTP Response를 압축했다면 서버는 결과가 어떤 알고리즘에 의해 인코딩(압축) 되었는가를 Content-Encoding 헤더를 통해 명시한다. 다음은 http://www.google.co.kr 에서 반환한 HTTP Response 헤더의 내용이다.
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html
Content-Encoding: gzip
Server: GWS/2.1
Content-Length: 1865
Date: Thu, 14 Jul 2005 14:21:24 GMT
구글은 Content-Encoding 헤더 값에 gzip에 명시하여, 컨텐츠가 gzip 알고리즘에 의해 압축되었음을 브라우저에게 알리고 있다.
Test
직접 테스트하여 눈으로 HTTP 압축이 수행되는 것을 살펴보자. 먼저 Fiddler를 수행시킨다. 그리고 IE를 수행시키고 http://www.yahoo.com 에 접속해 보자. 그러면 Fiddler에 IE가 전송하는 HTTP Request 헤더와 Yahoo 사이트가 반환하는 HTTP Response 헤더가 다음과 같이 표시될 것이다. 그리고 사이트가 반환하는 실제 컨텐츠(TextView 버튼을 클릭해 보라)는 HTML 이 아닌 바이너리 임을 알 수 있을 것이다. IE 브라우저가 압축을 풀고 그 결과를 표시하는 것이다.

<<IE의 Accept-Encoding 값 과 Yahoo 사이트의 Content-Encoding 값>>
이제 동일한 사이트에 대해 Accept-Encoding 을 명시하지 말아보자. Fiddler의 오른쪽 패널에서 Request Builder 탭을 선택하고 HTTP Request를 '생성'해 보자. URL 입력란에 Yahoo 사이트를 입력하고 Execute 버튼을 클릭하면 HTTP Request 가 만들어지고 이것이 수행될 것이다. 그리고 나서 HTTP Response 결과를 살펴보자. Request에서 Accept-Encoding이 명시되지 않았으므로, 웹 서버 역시 압축을 수행하지 않았음을 알 수 있다. 즉, Content-Encoding 이 명시되지 않았을 뿐더러 TextView 버튼을 눌러보면 HTML이 압축되지 않은 상태로 반환되었음을 확인하자.

<< HTTP 호출 만들기 >>
HTTP Compression Implementation
대략적으로 원리를 알아보았으니 구현을 어떻게 하면 될지 감이 잡힐 것이다. 웹 서버 구현이라면 클라이언트로부터 Accept-Encoding을 통해 클라이언트가 압축을 지원하는지 검사하고 지원한다면 컨텐츠를 압축한다. 그리고 Reponse 메시지에 Content-Encoding을 명시해 주면 될 것이다. 클라이언트의 경우, IE와 같은 브라우저를 사용한다면 이미 구현이 다 되어 있으므로 아무런 작업을 수행할 필요가 없다. 하지만 System.Net 네임스페이스의 HttpWebRequest 클래스 및 HttpWebResponse 클래스를 사용한다면 직접 구현이 필요할 것이다. HttpWebReqest 클래스에 Accept-Encoding을 명시해 주고 HttpWebResponse에서 Content-Encoding을 검사하여 압축되었다면 압축을 해제하면 된다. 다음 코드는 SharpZipLib 라이브러리를 이용하여 압축된 HTTP 컨텐츠를 압축 해제 하는 예제 코드이다.
using System;
using System.IO;
using System.Net;
using ICSharpCode.SharpZipLib.GZip;
class HttpDecompressTest
{
// HTTP 압축 해제 예제 코드
[STAThread]
static void Main(string[] args)
{
string url = "http://www.google.co.kr";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
// gzip 압축 허용
req.Headers["Accept-Encoding"] = "gzip";
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
string contentEncoding = res.Headers["Content-Encoding"];
Stream httpStream, resultStream;
httpStream = res.GetResponseStream();
// 압축 여부 확인
if (contentEncoding == "gzip") {
// SharpZipLib의 압축 해제 스트림 사용
resultStream = new GZipInputStream(httpStream);
}
else {
resultStream = httpStream;
}
// 간단한 구현이므로 euc-kr로 하드 코딩.
System.Text.Encoding encoding = System.Text.Encoding.GetEncoding("euc-kr");
// 결과 표시
StreamReader reader = new StreamReader(resultStream, encoding);
Console.WriteLine(reader.ReadToEnd());
resultStream.Close();
}
}
<< HTTP 압축 해제 예제 코드 >>
위 코드에서 Accept-Encoding을 설정하는 부분을 유심히 살펴볼 필요가 있다. 이 설정이 없는 경우 구글 사이트는 압축을 수행하지 않을 것이다. 또한 Accept-Ecoding을 설정해 놓은 상태에서 압축을 풀지 않도록 코드를 바꾸고 결과를 살펴보자. 압축을 풀지 않으면 HTML이 아닌 요상스런 문자들이 화면을 가득메우게 될 것이다.
대부분의 경우 클라이언트로 IE를 사용하기 때문에 클라이언트의 문제는 거의 없을 것이다. 사실 중요한 것은 웹 서버의 구현이다. 만약 CGI나 ISAPI Extension으로 사이트가 구성되어 있다면 압축을 어케 시도해 볼텐데, 당췌 ASP 나 ASP.NET으로 구현된 사이트에 압축을 적용할려치면 눈 앞이 답답하고 눈알이 튀어나올려고 할 것이다. 게다가 압축을 위해 기존 코드를 수정해야 한다면 더욱 미칠 노릇 아닌가?
다음 포스트에는 프로그램 소스를 전혀 수정하지 않고(당연히 그래야 할것이다) 웹 서버측에서 HTTP 압축을 수행하는 방법들에 대해 살펴보도록 하겠다. 특히 IIS 6.0의 압축 기능에 대해서 말이다. 궁금하지? 기둘리~~~