티스토리 뷰

개발/아파치와 톰캣

AJP 요청 헤더

jongqui 2018. 10. 27. 00:09

이슈 처리하다가 AJP 프로토콜에 대해 공부해야할 일이 생겼다.

이슈 내용은 AJP 요청 header의 payload length가 0일 때 요청을 제대로 처리 못한다는 것이었다.

문제는 요즘 아파치나 IIS에서는 payload length에 0을 넣어서 보내지 않는다는 것이었다.

그래서 테스트를 위해 AJP 구조에 대해 공부를 해야 했다.


참고로 이 포스팅에 있는 모든 내용은

https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html

에 있습니다.


AJP 프로토콜에서는 아파치가 클라이언트, J2EE 서버가 서버 역할이다.

아파치가 앞단에서 브라우저로부터의 요청을 받고, 그것을 파싱해 서버에게 넘긴다.

그림으로 표현하면 아래와 같다.





브라우저는 아파치로 HTTP 요청을 보낸다(꼭 browser일 필요는 없다)

아파치는 받은 요청을 가공해 AJP로 요청을 보낸다.

아파치에는 4byte header가 있다.

처음 2byte는 0x1234 이다. 이는 magic number 역할로, 메시지 시작을 알린다.

그 다음 2byte는 문제가 된 payload length 이다. 


AJP13 프로토콜 공식문서를 보면 다음과 같은 설명이 있다.

Integer는 2byte. big endian을 따른다.

boolean은 1byte로 0은 false 나머지는 true

String은 가변길이 문자열이다. C언어와 마찬가지로 문장의 끝에 \0이 들어간다.

byte : 말그대로 그냥 1byte


스펙에 따르면, 패킷의 최대 크기는 8192 byte이다. 고로 body에 실어서 보낼 수 있는 최대 데이터는 8188bytes이다.


하지만 이게 끝이 아니다.


헤더 안에 헤더가 또 있다.



AJP 헤더의 payload length는 너무나 당연히 AJP 요청헤더의 byte 개수도 카운트 한다.

먼저, http 요청이 아파치 서버로 들어오면 아파치에선 데이터를 가공해 AJP 요청헤더를 만든다.

맨 처음의 요청은 AJP 요청 헤더에 "Forward Request"  타입을 지정한다.(설정에 따라 CPING이 먼저 날아오기도 하지만 이건 생략)

http가 text 기반 프로토콜로 설계된 덕에 발생한 모든 에로사항을 거르기 위해, 이부분은 1byte 로 지정하는데 

Foword Request 같은 경우엔 0x02 이다.


그 다음엔 method byte가 온다. 이 method byte는 HTTP method를 말하는 것이다. 이것도 1byte이다.



사실 더 있긴한데, 자세한 것은 위에 언급한 링크에 다 있다.


그 다음은 내가 사용하는 protocol을 지정한다. 여기선 HTTP/1.1을 사용하므로 text로 그대로 써주면 된다.



그 다음이 J2EE 서버 주소, host, 아파치 서버네임, 서버포트가 온다.

그리고 SSL 사용여부를 체크하는 1 byte가 오고 header의 개수를 지정한다. 이 때 header의 개수는 http header 말하는 것이다.

그리고 request header들이 나오고, 서버에서 사용할 attribute가 있으면 그것도 전송한다.

마지막은 0xFF로 메시지의 끝을 알린다.



AJP13_FORWARD_REQUEST :=
    prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
    method           (byte)
    protocol         (string)
    req_uri          (string)
    remote_addr      (string)
    remote_host      (string)
    server_name      (string)
    server_port      (integer)
    is_ssl           (boolean)
    num_headers      (integer)
    request_headers *(req_header_name req_header_value)
    attributes      *(attribut_name attribute_value)
    request_terminator (byte) OxFF

출처 : https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html



request uri 는 localhost:8088/examples/index.jsp 에서 /examples/index.jsp 부분이다.

remote는 J2EE server를, server는 아파치 서버를 의미한다.

num_headers는 여기선 http header의 개수를 의미한다.

request_terminator는 헤더의 끝을 의미한다.


request headers 부분을 다시 한 번 살펴보면, method를 1byte로 줄였듯이, 이쪽도 헤더들을 2byte로 줄여놨다.



NameCode valueCode name
accept0xA001SC_REQ_ACCEPT
accept-charset0xA002SC_REQ_ACCEPT_CHARSET
accept-encoding0xA003SC_REQ_ACCEPT_ENCODING
accept-language0xA004SC_REQ_ACCEPT_LANGUAGE
authorization0xA005SC_REQ_AUTHORIZATION
connection0xA006SC_REQ_CONNECTION
content-type0xA007SC_REQ_CONTENT_TYPE
content-length0xA008SC_REQ_CONTENT_LENGTH
cookie0xA009SC_REQ_COOKIE
cookie20xA00ASC_REQ_COOKIE2
host0xA00BSC_REQ_HOST
pragma0xA00CSC_REQ_PRAGMA
referer0xA00DSC_REQ_REFERER
user-agent0xA00ESC_REQ_USER_AGENT



이번 이슈에서 주목해야할 헤더는 content-length 이다.

일반적인 POST 요청에는 body가 들어있고, content length 헤더를 붙여서 보낸다.

굳이 이번 이슈만이 아니라, AJP 프로토콜에 대해 이해하는데 가장 중요한 부분이라고 할 수 있다.



AJP13 Forward Request 요청을 받은 서버는 content length에 기반해 요청이 얼마나 남았는지 검사한다.

앞에서 언급했듯이, 최대 8188 byte를 body에 실어서 보낼 수 있다.

이미지를 전송했다든지 하는 경우엔 한번에 가지 않을 수 있고, 이 경우에 대비한 것이다.

content length에 기반에 요청이 덜왔으니 다음 걸 달라고 부지런히 응답을 내보내는 것이다.

body를 다받았으면, 다받았다고 응답을 보낸다. 


참고로 이 때 보내는 body의 구조는 



이런 구조다.

AJP Request header가 없고, 그냥 데이터를 8188byte 만큼 꽉 채워서 보낸다.


이번 이슈에서 문제가 되었던 부분은 아파치 측에서 더 줄 데이터가 없는 경우에 payload length를 0으로 넣어서 보낸 것이다.

content-length 없이 POST 요청을 보낼 때, 이런 경우가 발생한다고 하는데, 요새 브라우저들이 그러질 않아서 재현을 못했다...


참고로, 위에서 등장하는 모든 string들의 앞에는 해당 string의 길이를 같이 적어줘야 한다.

아래 테스트를 위해 만들었던 앱을 첨부했으니 필요하면 참고하시길...


test.py



'개발 > 아파치와 톰캣' 카테고리의 다른 글

Tomcat HTTP location Header 이슈  (1) 2019.08.18
자바 어플리케이션 inputstream 주의사항  (0) 2019.01.20
ajp 요청 헤더2  (0) 2019.01.20
ajp 프로토콜 설정  (0) 2018.07.08
아파치 간단 빌드  (0) 2018.07.06
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함