hooking 함수¶
M2 후킹(hooking) 함수를 이용하면 자유롭게 HTTP 트랜잭션을 제어할 수 있다.
클라이언트 HTTP 요청에 대한 재정의
캐싱키 정의
원본 HTTP 요청에 대한 재정의
클라이언트 요청을 M2의 hooking 함수로 보낸다.
hooking 함수는 캐싱키와
TCP_MISS
시 원본에 보낼 요청을 정의하여 응답한다.200 OK
가 아니라면 M2RT는403 Forbidden
을 응답한다.재정의된 캐싱키를 사용해 캐싱엔진에서 찾는다.
원본 요청 시 hooking 함수가 정의한 요청 모델을 참조해 원본서버에 요청한다.
Note
Purge의 경우 2, 3 항에서 사용하는 캐싱 키를 사용한다.
설정¶
hosting[].hook
설정을 통해 확장 커스터마이징을 구성한다.
{
"hosting": [
{
"name": "www.foo.com",
"hook": {
"enable": true,
"path": "https://example.com/sample.js"
}
}
]
}
예를 들어 다음과 같이 임의의 hooking 함수전용 설정이 필요할 수 있다.
{
"name": "John",
"age": 30,
"car": null
}
설정은 hooking 함수에 파라미터로 전달되는데 hosting[].hook.session.param
에 값으로 설정한다.
See also
{
"hosting": [
{
"name": "www.foo.com",
"hook": {
"enable": true,
"path": "https://example.com/sample.js",
"session": {
"param": "{ \"name\": \"John\", \"age\": 30, \"car\": null }"
}
}
}
]
}
Note
hosting[].hook.session.param
을 ESCAPE & 직렬화해야 하는 이유는 setting.json
의 표준 DTD로 관리가 불가능하기 때문이다.
다시 말해 setting.json
의 정규기능이 아닌 설정이 setting.json
설정구조에 들어가는 것을 방지하기 위함이다.
클라이언트 요청후킹¶
클라이언트가 보낸 HTTP 요청을 hooking 함수가 재정의 할 수 있도록 구조화하여 전달한다.
{
"host": "foo.com",
"clientIp": "181.43.1.33",
"sessionId": 2,
"protocol": "http",
"message": "POST /itemimage/LO/12/37/50/02/80/vdo/LO1237500280_1.mpx3123 HTTP/1.1\r\nHost: foo.com\r\nContent-Type: text/plain\r\nUser-Agent: PostmanRuntime/7.26.8\r\nAccept: */*\r\nPostman-Token: 0bce4527-7d8b-4974-9c2c-742efb8a549c\r\nAccept-Encoding: gzip, deflate, br\r\nConnection: keep-alive\r\nContent-Length: 519\r\nX-Forwarded-For: 181.43.1.33\r\n\r\n",
"body": "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n <s:Body>\r\n <serviceCall xmlns=\"http://webservice.B2BOnline.com\">\r\n <AvailRQ>\r\n <AgencyId>JJSEL13157</AgencyId>\r\n <CarrierCode>7C</CarrierCode>\r\n <DepApoCode>CJU</DepApoCode>\r\n <DepApoName></DepApoName>\r\n <ArrApoCode>PUS</ArrApoCode>\r\n <ArrApoName></ArrApoName>\r\n <FlightDate>20171228</FlightDate>\r\n <PaxCount>1</PaxCount>\r\n </AvailRQ>\r\n </serviceCall>\r\n </s:Body>\r\n</s:Envelope>"
"param": { "name": "John", "age": 30, "car": null },
"functions": null
}
host
요청을 처리하는 가상호스트 이름
clientIp
소켓 리모트 주소
sessionId
세션 고유번호 ( access.log 의
session-id
필드와 동일)protocol
프로토콜.
http
또는https
또는http2
message
클라이언트 요청의 HTTP 메시지
body
클라이언트 POST 요청의 HTTP Body. POST 요청이 아니라면 해당 필드가 없거나 값이
null
param
hosting[].hook.param
에 설정된 고객사 전용설정. Unescaped JSON으로 전달된다.functions
연계될 함수체인 정보
# 함수체인이 message에 명시되어 있다면 functions필드가 추가된다. { ... "message": "GET /sample.zip/unzip/files/logo.jpg/dims/resize/100x100 ... (생략)... ", .. "functions": [ { "name": "unzip", "url": "/unzip/files/logo.jpg" }, { "name": "dims", "url": "/dims/resize/100x100" } ] }
Important
개발 호환성을 위해 요청 헤더에
Content-Type: application/json
를 명시한다.RT
는 Hooking함수를 호출할 때 로그분석을 위해X-M2X-Forwarded-Context-Id
헤더를 포워딩한다. hooking 함수에서 외부통신을 위해RT
를 이용하는 경우 반드시X-M2X-Forwarded-Context-Id
헤더를 명시해주어야 같은x-ctx-id
로 access.log와 origin.log에 기록된다.
에러 처리¶
다음과 같이 code
를 통해 요청이 더 진행되지 못하도록 에러처리할 수 있다.
{
"name": "m2hook1",
"code": 403,
"body": "<HTML><TITLE>403 Forbidden</TITLE><BODY><H1>Forbidden</H1></BODY></HTML>"
}
name
m2hook1 (고정)
code
200 OK
를 보내지 않는다면510 Not Extended
응답과 함께 오류 메시지를 보낸다.body
응답 바디
로깅¶
hooking 함수도 함수체인에 속하기 때문에 origin.log
에 기록된다.
See also
주요 로그필드는 다음과 같다.
session-type
hook1 으로 기록된다.x-sc-chain-error
Hooking함수 에러 메시지x-sc-chain-info
Hooking함수 정보 메시지. 주로 캐싱키를 기록한다.
요청 재정의¶
hooking 함수의 응답에 클라이언트 HTTP 요청을 재정의한다.
{
"sessionId": 2,
"response": {
"code": 100,
"body": "blah blah",
"headers": [
{ "key": "my-powered-by", "value": "winesoft" },
{ "key": "cookie", "value": "NNB=LS3KUV63E5RV6; NRTK=ag#all_gr#1_ma#-2_si#0_en#0_sp#0;" }
]
},
"request": null,
"cacheKey": "/availity?key={a,b,1}",
"vhost": "bar.com",
"originRequest": {
"method": "POST",
"url": "/itemimage/LO/12/37/50/02/80/vdo/LO1237500280_1.mpx3123",
"body": "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n <s:Body>\r\n <serviceCall xmlns=\"http://webservice.B2BOnline.com\">\r\n <AvailRQ>\r\n <AgencyId>JJSEL13157</AgencyId>\r\n <CarrierCode>7C</CarrierCode>\r\n <DepApoCode>CJU</DepApoCode>\r\n <DepApoName></DepApoName>\r\n <ArrApoCode>PUS</ArrApoCode>\r\n <ArrApoName></ArrApoName>\r\n <FlightDate>20171228</FlightDate>\r\n <PaxCount>1</PaxCount>\r\n </AvailRQ>\r\n </serviceCall>\r\n </s:Body>\r\n</s:Envelope>",
"headers": [
{ "key": "x-custom-header", "value": "abcdefg" },
{ "key": "x-custom-header2", "value": "baq.com" },
{ "key": "cookie", "value": "NNB=LS3KUV63E5RV6; NRTK=ag#all_gr#1_ma#-2_si#0_en#0_sp#0;" }
]
}
}
Note
요청을 재정의하지 않고 바이패스 시키고 싶다면 다음과 같이 응답한다.
{
"sessionId": 2,
"response": {
"code": 100
},
"cacheKey": null
}
response.code
를100
으로 설정하여 요청을 진행시킨다.cacheKey
를null
로 설정하여 캐싱엔진을 우회시키도록 한다.
sessionId
세션 고유번호 (디버그 용, USERDATA 개념)
response
클라이언트 요청 처리응답
code
값이
100
인 경우 흐름을 지속한다. 그 외에는 트랜잭션을 더 진행하지 않고 정의된code
,body
,headers
를 즉시 응답한다.body
즉시 응답할 경우 HTTP Body 데이터.
headers
HTTP Headers. 바이패스를 제외한 모든 응답에 명시된다.
request
클라이언트 요청 재정의
cacheKey
캐싱엔진에서 사용할 키
cacheTtl (단위: 초)
캐싱엔진에서 사용할 TTL(Time To Live). 원본이
2xx
계열로 응답할 때만 적용된다.cacheResult
access.log 의
sc-cachehit
필드를 재정의한다.Note
만약 Hook에서 클라이언트 트랜잭션을 종료할 경우 캐시는 요청거부로 판단하여
TCP_DENY
로 기록한다.vhost
변경될 가상호스트. 이 값이 NULL 또는 빈문자열 이라면 가상호스트를 변경하지 않는다.
originRequest
원본에 요청해야 하는 경우 HTTP 요청 구조체
method
원본요청 method
Warning
클라이언트
HEAD
메소드 요청이라면GET
으로 응답해야 한다.url
원본요청 URL
body
원본요청 HTTP Body 데이터.
headers
HTTP Headers
Warning
주의사항
서버로 보내는 HTTP 헤더를 설정할 뿐이지 클라이언트가 전송한 헤더가 덮어씌워지는 것은 아님에 주의한다. 만약 Hook을 통해 조작한 의도를 다른 기능과 연계하려면
cacheKey
에 그 의도를 담아야 한다.host
헤더는 재정의되지 않는다. 정확히는 여기에 설정되어도 캐싱엔진에서 원본 요청시 항상 덮어 쓰기 때문에 동작하지 않는다.만약 임의의 서버로 보내고 싶다면 proxy 함수를 사용한다.
instant
바이패스로 동작할 경우 클라이언트 헤더보다 여기서 재정의한 헤더가 우선한다.
POST 요청 상세¶
POST 요청을 hooking 하려면 다음 설정이 선행되어야 한다.
# functions.network.http.frontEnd.bypass
"postMethod": {
"enable": true
}
# functions.network.cache.cachingKey
"postMethod": {
"enable": true,
"bodySensitive": true,
"bodyContentLengthMax": 102400
}
바이패스하는
POST
요청이라면 Hooking을 통한 재정의는 불필요하다.hooking 모듈을 동작시키려면 POST요청을 캐싱해야 한다.
캐싱엔진은 POST
요청에 대해 URL과 Body의 조합으로 캐싱키를 생성한다.
hooking 모듈에 의해 요청이 재정의될 경우 다음과 같은 규칙을 따른다.
캐싱키는 hooking 응답의
cacheKey
만을 사용한다. 클라이언트POST
요청의 URL 및 Body는 무시된다.캐싱엔진이 원본에 요청을 보낼 때는 hooking 응답의
originRequest
만을 사용한다. 캐싱키 및 클라이언트 요청은 모두 무시된다.
정리하면 hooking 모듈은 요청을 완전히 재정의하는 개념이기 때문에 POST
요청은 hooking 모듈로 전달되기 전까지만 의미를 가진다고 볼 수 있다.