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또는http2message클라이언트 요청의 HTTP 메시지
body클라이언트 POST 요청의 HTTP Body. POST 요청이 아니라면 해당 필드가 없거나 값이
nullparamhosting[].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>"
}
namem2hook1 (고정)
code200 OK를 보내지 않는다면510 Not Extended응답과 함께 오류 메시지를 보낸다.body응답 바디
로깅¶
hooking 함수도 함수체인에 속하기 때문에 origin.log 에 기록된다.
See also
주요 로그필드는 다음과 같다.
session-typehook1 으로 기록된다.x-sc-chain-errorHooking함수 에러 메시지x-sc-chain-infoHooking함수 정보 메시지. 주로 캐싱키를 기록한다.
요청 재정의¶
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;" }
]
},
"userData": null
}
Note
요청을 재정의하지 않고 바이패스 시키고 싶다면 다음과 같이 응답한다.
{
"sessionId": 2,
"response": {
"code": 100
},
"cacheKey": null
}
response.code를100으로 설정하여 요청을 진행시킨다.cacheKey를null로 설정하여 캐싱엔진을 우회시키도록 한다.
sessionId세션 고유번호 (디버그 용, USERDATA 개념)
response클라이언트 요청 처리응답
code값이
100인 경우 흐름을 지속한다. 그 외에는 트랜잭션을 더 진행하지 않고 정의된code,body,headers를 즉시 응답한다.body즉시 응답할 경우 HTTP Body 데이터.
headersHTTP Headers. 바이패스를 제외한 모든 응답에 명시된다.
request클라이언트 요청 재정의
cacheKey캐싱엔진에서 사용할 키
cacheTtl (단위: 초)캐싱엔진에서 사용할 TTL(Time To Live). 원본이
2xx계열로 응답할 때만 적용된다.cacheResultaccess.log 의
sc-cachehit필드를 재정의한다.Note
만약 Hook에서 클라이언트 트랜잭션을 종료할 경우 캐시는 요청거부로 판단하여
TCP_DENY로 기록한다.vhost변경될 가상호스트. 이 값이 NULL 또는 빈문자열 이라면 가상호스트를 변경하지 않는다.
originRequest원본에 요청해야 하는 경우 HTTP 요청 구조체
method원본요청 method
Warning
클라이언트
HEAD메소드 요청이라면GET으로 응답해야 한다.url원본요청 URL
body원본요청 HTTP Body 데이터.
headersHTTP Headers
Warning
주의사항
서버로 보내는 HTTP 헤더를 설정할 뿐이지 클라이언트가 전송한 헤더가 덮어씌워지는 것은 아님에 주의한다. 만약 Hook을 통해 조작한 의도를 다른 기능과 연계하려면
cacheKey에 그 의도를 담아야 한다.host헤더는 재정의되지 않는다. 정확히는 여기에 설정되어도 캐싱엔진에서 원본 요청시 항상 덮어 쓰기 때문에 동작하지 않는다.만약 임의의 서버로 보내고 싶다면 proxy 함수를 사용한다.
instant바이패스로 동작할 경우 클라이언트 헤더보다 여기서 재정의한 헤더가 우선한다.
userData사용자 정의 access.log 기록을 위한 필드. 하위 1 depth까지만 인식한다.
"userData": { "myfield": "custom-field", "mystatus": "custom-status" }
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 모듈로 전달되기 전까지만 의미를 가진다고 볼 수 있다.