소 예 공 방

HTTP 1.1 메시지 형식

길위의행복 2012. 9. 18. 21:44

HTTP 요청 메시지를 파싱하고 그에 대한 응답 메시지를 구성할 수 있으려면 어느 정도의 지식이 필요할까? 이야기를 진행하기 전에 먼저 다루고자 하는 범위부터 정하는 것이 좋겠다.


    1) GET 방식의 요청 메시지와 HTML 형식의 응답 문서.

    2) POST 방식의 요청 메시지와 HTML 형식의 응답 문서. 요청 메시지에 폼 데이터가 포함되어 있다면, URL 인코딩되어 있는 경우만 처리한다. 파일 업로드와 같이 멀티파트 형식의 폼 데이터는 여기서 다루지 않는다.


HTTP 1.1을 정의하고 있는 문서는 176쪽으로 이루어져 있다. 이 중에서 HTTP 메시지에 대한 내용을 두 쪽 분량 정도의 지식으로 정리해서 위에서 정의한 두 가지 기능을 수행하는 라이브러리를 작성할 수 있도록 하였다. 또한 뒷 부분에서는 멀티파트 폼 데이터, 전송 코딩, 그리고 좀 더 고려할 사항들을 제시하여 나중에 기능을 추가하거나 확장하고자 할 때 참고할 수 있도록 하였다.


1. HTTP 메시지


HTTP 메시지는 클라이언트에서 서버로 보내는 요청 메시지와 서버에서 클라이언트로 보내는 응답 메시지로 이루어진다.


    HTTP-message   = Request | Response     ; HTTP/1.1 messages


요청과 응답 메시지는 종류에 관계없이 다음의 형식을 따른다.


    generic-message = start-line

                      *(message-header CRLF)

                      CRLF

                      [ message-body ]

    start-line      = Request-Line | Status-Line


1.1 메시지 시작 줄


start-line은 메시지 종류에 따라 아래와 같이 구분한다.


    요청 메시지:


        Request-Line   = Method SP Request-URI SP HTTP-Version CRLF


    응답 메시지:


        Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF


Method는 다음과 같은 값을 가질 수 있고, 대소문자를 구별한다.


    Method         = "OPTIONS"

                      | "GET"

                      | "HEAD"

                      | "POST"

                      | "PUT"

                      | "DELETE"

                      | "TRACE"

                      | "CONNECT"

                      | extension-method

       extension-method = token


1.2 메시지 헤더


이름과 값의 쌍인 헤더 필드는 한 줄로 이루어지고, 헤더 필드가 아예 없거나 연속해서 여러 개가 존재할 수 있다. 이름은 대소문자를 구분하지 않는다. 콜론과 값 사이에는 여러 개의 LWS가 올 수 있는데, 한 개의 SP가 바람직하다.


    message-header = field-name ":" [ field-value ]


각각의 헤더 필드는 다음 네 가지 범주로 나누어서 사용한다.


    general-header

    request-header 또는 response-header

    entity-header


헤더 필드가 어떤 순서로 오느냐는 중요하지 않지만, 통상적으로 위와 같은 순서로 배치한다.


1.3 메시지 헤더의 끝


줄이 시작하는 부분에 CRLF가 있으면 헤더가 끝났다고 간주한다.


1.4 메시지 본체


헤더 필드 중에 Content-Type이 값을 가지고 있으면, 그 값에 따라 메시지 본체가 온다. 기본적으로 폼 데이터를 실은 요청 메시지인 경우 Content-Type의 값으로 "application/x-www-form-urlencoded"를 가진다. 이 경우에는 폼 데이터를 아래와 같이 인코딩해서 보낸다.


    1) 폼의 필드와 값을 name=value으로 만든다.

    2) 여러 개의 필드를 &로 연결한다.

    3) 공백은 +로 치환한다. JavaScript는 공백을 %20으로 치환한다.

    4) alphanumeric이 아닌 문자의 경우 % HEX HEX로 치환한다.


파일 업로드를 위한 폼 데이터의 경우 Content-Type의 값으로 "multipart/form-data"가 올 수 있다.


메시지 본체의 길이는 헤더 Content-Length의 값으로 알 수 있다. 지금까지 다룬 내용으로 기본적인 요청/응답 메시지를 다룰 수 있다.


2. 멀티파트 폼 데이터


파일 업로드를 위한 폼 데이터를 멀티파트 형식으로 지정하여 요청 메시지를 보낼 수 있다.


3. 전송 코딩


메시지 본체를 다루기 위해서 한 가지 더 고려해야 할 헤더가 있다. 그것은 Transfer-Encoding이다. 이것은 말 그대로 전송과 관련된 데이터 인코딩이다. 그 값이 chunked인 경우 메시지 본체에 변화가 가해지고 Content-Length도 그대로 사용할 수 없게 된다.


4. 더 고려할 사항들


4.1 Request-Line 앞의 CRLF


HTTP/1.0 클라이언트 애플리케이션 중에는 POST request 뒤에 CRLF를 덧붙이는 경우가 있다. 이것은 HTTP/1.1에서 허용하지 않는 것이지만 Request-Line 앞에 오는 CRLF를 무시함으로써 문제를 해결할 수 있다.


4.2 긴 헤더 필드


헤더의 값 부분이 길 경우 편의상 여러 줄로 나누어서 표현할 수 있다. 표현 방법은 적당한 위치에 CRLF를 넣고 바로 뒤에 한 개 이상의 LWSP를 추가하는 것이다. 따라서 헤더의 값을 읽을 때는 CRLF 뒤에 한 개 이상의 LWSP가 있으면 CRLF와 LWSP를 버림으로써 헤더의 값을  구성할 수 있다.


5. 참고 문헌


"Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.

    http://tools.ietf.org/html/rfc2616


Crocker, D., "Standard for The Format of ARPA Internet Text Messages", STD 11, RFC 822, August 1982,

    http://tools.ietf.org/html/rfc822