Node.js로 간단한 WAS를 구현하면서 직접 HTTP 메시지 파싱 기능을 만들어보았다. 처음에는 HTTP 요청을 받아 파싱하는 과정이 단순할 것이라 생각했지만, 실제 구현 과정에서는 다양한 예외 케이스를 마주했다.
특히, 요청이 예상과 다르게 분할되거나 헤더와 바디의 경계를 처리하는 과정에서 난관이 많았다. 같은 문제로 고생하는 다른 캠퍼들도 많았고, 문득 스프링에서는 HTTP 메시지를 어떻게 파싱하고 있는지가 궁금해졌다. 직접 라이브러리 코드를 분석해보니, 예상과는 다르게 동작하는 부분이 많았다.
스프링에서의 HTTP 메시지 파싱 방식
스프링이 내부적으로 HTTP 요청을 처리하는 방식을 살펴보면, 기본적인 흐름은 다음과 같다.
1. 포인터 방식으로 HTTP 메시지를 한 글자씩 읽어 나간다.
2. 헤더와 바디를 한꺼번에 분리하는 것이 아니라, 먼저 헤더를 파싱한 후 바디를 파싱한다.
3. 바디 파싱 시 Content-Length 값을 참조하여 데이터를 정확히 읽는다.
4. HTTP 요청이 여러 개 버퍼에 쌓여 있으면, 다음 요청의 헤더를 읽고 바디를 읽는 과정을 반복한다.
5. 헤더가 중간에 잘리면 추가 데이터를 기다리는 방식으로 처리한다. 즉, 요청 전체를 한 번에 파싱하는 것이 아니라, "헤더 파싱 → 바디 파싱 → 다음 요청 헤더 파싱 → 다음 요청 바디 파싱" 순서로 진행된다.
이 과정에서 헤더가 잘리는 경우(requestLineParsing 플래그를 true로 변경) 데이터를 추가로 기다리는 로직이 들어가 있으며, Tomcat의 Http11InputBuffer나 Http11Processor에서 이러한 처리를 담당하는 코드를 확인할 수 있다.
관련 코드 링크
HttpHeaderParser.java (헤더 파싱 처리)
'Backend > Spring' 카테고리의 다른 글
[Spring] 스프링으로 서블릿을 어떻게 다룰까? - (2) 서블릿 컨테이너와 Dispatcher Servlet의 도입 (0) | 2024.03.10 |
---|---|
[Spring] 스프링으로 서블릿을 어떻게 다룰까? - (1) 서블릿 (0) | 2024.03.06 |