feat: add http response module for runner.
diff --git a/src/runner/http/response.py b/src/runner/http/response.py
new file mode 100644
index 0000000..b3d1968
--- /dev/null
+++ b/src/runner/http/response.py
@@ -0,0 +1,161 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from __future__ import annotations
+import flatbuffers
+import runner.http.protocol as RunnerHttpProtocol
+from a6pluginproto import TextEntry as A6TextEntry
+from a6pluginproto.HTTPReqCall import Stop as A6HTTPReqCallStop
+from a6pluginproto.HTTPReqCall import Resp as A6HTTPReqCallResp
+from a6pluginproto.HTTPReqCall import Action as A6HTTPReqCallAction
+from a6pluginproto.PrepareConf import Resp as A6PrepareConfResp
+from a6pluginproto.Err import Resp as A6ErrResp
+from a6pluginproto.Err import Code as A6ErrCode
+
+RESP_MAX_DATA_SIZE = 2 << 24 - 1
+
+
+class Response(object):
+
+ def __init__(self, rpc_type: int):
+ self.response = {}
+ self.initResponse()
+ self.setRpcType(rpc_type)
+
+ def setRpcType(self, rpc_type: int) -> Response:
+ self.response["rpc_type"] = rpc_type
+ return self
+
+ def getRpcType(self) -> int:
+ return self.response.get("rpc_type", 0)
+
+ def setId(self, id: int) -> Response:
+ self.response["id"] = id
+ return self
+
+ def getId(self) -> int:
+ return self.response.get("id", 0)
+
+ def setToken(self, token: int) -> Response:
+ self.response["token"] = token
+ return self
+
+ def getToken(self) -> int:
+ return self.response.get("token", 0)
+
+ def setBody(self, value: str) -> Response:
+ self.response["body"] = value
+ return self
+
+ def getBody(self) -> str:
+ return self.response.get("body", "")
+
+ def getHeaders(self) -> dict:
+ return self.response.get("headers", {})
+
+ def setHeader(self, key: str, value: str) -> Response:
+ if not self.response.get("headers", None):
+ self.response["headers"] = {}
+ self.response["headers"][key] = value
+ return self
+
+ def getHeader(self, key: str) -> str:
+ if not self.response.get("headers", None):
+ return ""
+ return self.response.get("headers").get(key, "")
+
+ def getStatusCode(self) -> int:
+ return self.response.get("statusCode", 0)
+
+ def setStatusCode(self, code: int) -> Response:
+ self.response["statusCode"] = code
+ return self
+
+ def resetResponse(self) -> None:
+ self.initResponse()
+
+ def initResponse(self) -> None:
+ self.response = {
+ "body": "",
+ "headers": {},
+ "statusCode": 0,
+ }
+
+ def responseHasChange(self) -> bool:
+ return self.response.get("body") or \
+ self.response.get("headers") or \
+ self.response.get("statusCode")
+
+ def responseToFlatBuffers(self) -> flatbuffers.Builder:
+ rpcType = self.getRpcType()
+ builder = RunnerHttpProtocol.newBuilder()
+
+ if rpcType == RunnerHttpProtocol.RPC_PREPARE_CONF:
+ A6PrepareConfResp.Start(builder)
+ A6PrepareConfResp.AddConfToken(builder, self.getToken())
+ res = A6PrepareConfResp.End(builder)
+ builder.Finish(res)
+ elif rpcType == RunnerHttpProtocol.RPC_HTTP_REQ_CALL:
+ headerVector = None
+ headers = self.getHeaders()
+ if headers:
+ headerEntries = []
+ for hk in headers:
+ hv = headers[hk]
+ hkb = builder.CreateString(hk)
+ hvb = builder.CreateString(hv)
+ A6TextEntry.Start(builder)
+ A6TextEntry.AddName(builder, hkb)
+ A6TextEntry.AddValue(builder, hvb)
+ headerEntry = A6TextEntry.End(builder)
+ headerEntries.append(headerEntry)
+
+ headerSize = len(headerEntries)
+ A6HTTPReqCallStop.StartHeadersVector(builder, headerSize)
+ for i in range(headerSize - 1, -1, -1):
+ builder.PrependUOffsetTRelative(headerEntries[i])
+ headerVector = builder.EndVector()
+
+ bodyVector = None
+ body = self.getBody()
+ if body:
+ body = body.encode(encoding="UTF-8")
+ bodyVector = builder.CreateByteVector(body)
+
+ statusCode = self.getStatusCode()
+ A6HTTPReqCallStop.Start(builder)
+ if statusCode == 0:
+ A6HTTPReqCallStop.AddStatus(builder, 200)
+ else:
+ A6HTTPReqCallStop.AddStatus(builder, statusCode)
+ if headerVector:
+ A6HTTPReqCallStop.AddHeaders(builder, headerVector)
+ if bodyVector:
+ A6HTTPReqCallStop.AddBody(builder, bodyVector)
+ stop = A6HTTPReqCallStop.End(builder)
+
+ A6HTTPReqCallResp.Start(builder)
+ A6HTTPReqCallResp.AddId(builder, self.getId())
+ A6HTTPReqCallResp.AddActionType(builder, A6HTTPReqCallAction.Action.Stop)
+ A6HTTPReqCallResp.AddAction(builder, stop)
+ res = A6HTTPReqCallResp.End(builder)
+ builder.Finish(res)
+ else:
+ A6ErrResp.Start(builder)
+ A6ErrResp.AddCode(builder, A6ErrCode.Code.BAD_REQUEST)
+ res = A6ErrResp.End(builder)
+ builder.Finish(res)
+ return builder