Created
April 4, 2025 13:21
-
-
Save ad3n/bc04d465ba5b0970936ae7d44e03e254 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package requests | |
import ( | |
"io" | |
"lawang" | |
"lawang/bytes" | |
"lawang/configs" | |
"lawang/jsons" | |
"lawang/utils" | |
"net/http" | |
"net/url" | |
"path/filepath" | |
"strings" | |
"github.com/gofiber/fiber/v3" | |
core "github.com/valyala/fasthttp" | |
) | |
type Context struct { | |
cacheKey string | |
requestID string | |
clientIp string | |
params map[string]string | |
queries map[string]string | |
headers http.Header | |
files map[string]*File | |
credential *lawang.Client | |
endpoint *configs.Endpoint | |
route *fiber.Route | |
fasthttpRequest *core.Request | |
request *Request | |
response *Response | |
timeout int | |
} | |
var contextPool = lawang.NewPool(func() *Context { | |
return &Context{} | |
}) | |
func (c *Context) CacheKey() string { return c.cacheKey } | |
func (c *Context) Credential() *lawang.Client { return c.credential } | |
func (c *Context) ClientIp() string { return c.clientIp } | |
func (c *Context) Endpoint() *configs.Endpoint { return c.endpoint } | |
func (c *Context) Files() map[string]*File { return c.files } | |
func (c *Context) Params() map[string]string { return c.params } | |
func (c *Context) Headers() http.Header { return c.headers } | |
func (c *Context) Queries() map[string]string { return c.queries } | |
func (c *Context) FastHttpRequest() *core.Request { return c.fasthttpRequest } | |
func (c *Context) RequestID() string { return c.requestID } | |
func (c *Context) Request() *Request { return c.request } | |
func (c *Context) Response() *Response { return c.response } | |
func (c *Context) Route() *fiber.Route { return c.route } | |
func (c *Context) SetCacheKey(cacheKey string) { c.cacheKey = cacheKey } | |
func (c *Context) SetCredential(credential *lawang.Client) { | |
if c.credential != nil { | |
lawang.ClientPool.Put(c.credential) | |
} | |
c.credential = credential | |
} | |
func (c *Context) SetRequest(request *Request) { | |
if c.request != nil { | |
RequestPool.Put(c.request) | |
} | |
c.request = request | |
} | |
func (c *Context) SetResponse(response *Response) { | |
if c.response != nil { | |
ResponsePool.Put(c.response) | |
} | |
c.response = response | |
} | |
func (c *Context) Reset() { | |
c.cacheKey, c.requestID, c.clientIp = "", "", "" | |
if c.params != nil { | |
lawang.MapStringPool.Put(c.params) | |
} | |
if c.queries != nil { | |
lawang.MapStringPool.Put(c.queries) | |
} | |
if c.files != nil { | |
for _, f := range c.files { | |
FilePool.Put(f) | |
} | |
clear(c.files) | |
} | |
c.credential, c.endpoint, c.route, c.fasthttpRequest = nil, nil, nil, nil | |
if c.request != nil { | |
RequestPool.Put(c.request) | |
} | |
if c.response != nil { | |
ResponsePool.Put(c.response) | |
} | |
c.timeout = 0 | |
clear(c.headers) | |
} | |
func ReleaseContext(ctx *Context) { | |
contextPool.Put(ctx) | |
} | |
func AcquireContext(cache *lawang.Cache, ctx fiber.Ctx, endpoint *configs.Endpoint) *Context { | |
context := contextPool.Get() | |
context.requestID = RequestID(ctx) | |
context.endpoint = endpoint | |
context.params = extractParams(ctx) | |
context.headers = extractHeaders(ctx) | |
context.queries = extractQueries(ctx) | |
context.files = parseFormData(ctx, endpoint) | |
context.route = ctx.Route() | |
context.fasthttpRequest = ctx.Request() | |
context.response = ResponsePool.Get() | |
context.clientIp = utils.ClientIp(ctx) | |
context.timeout = resolveTimeout(endpoint) | |
request := RequestPool.Get() | |
parse(context, request) | |
request.RawBody = parseBody(ctx) | |
context.request = request | |
return context | |
} | |
func parse(ctx *Context, request *Request) { | |
request.Protocol = bytes.ByteToString(ctx.FastHttpRequest().URI().Scheme()) | |
request.ClientIp = ctx.ClientIp() | |
request.Path = ctx.Route().Path | |
request.Uri = bytes.ByteToString(ctx.FastHttpRequest().RequestURI()) | |
request.Method = bytes.ByteToString(ctx.FastHttpRequest().Header.Method()) | |
request.Params = ctx.Params() | |
request.Headers = ctx.Headers() | |
request.Queries = ctx.Queries() | |
request.RawQuery = bytes.ByteToString(ctx.FastHttpRequest().URI().QueryArgs().QueryString()) | |
jsonParams, _ := jsons.Marshal(request.Params) | |
jsonQuery, _ := jsons.Marshal(request.Queries) | |
jsonHeaders, _ := jsons.Marshal(request.Headers) | |
request.ParamBytes = jsonParams | |
request.QueryBytes = jsonQuery | |
request.HeaderBytes = jsonHeaders | |
request.Files = ctx.Files() | |
} | |
func extractHeaders(ctx fiber.Ctx) http.Header { | |
headers := make(http.Header) | |
ctx.Request().Header.VisitAll(func(k, v []byte) { | |
headers.Set(bytes.ByteToString(k), bytes.ByteToString(v)) | |
}) | |
return headers | |
} | |
func extractQueries(ctx fiber.Ctx) map[string]string { | |
queries := lawang.MapStringPool.Get() | |
ctx.Request().URI().QueryArgs().VisitAll(func(k, v []byte) { | |
queries[bytes.ByteToString(k)] = bytes.ByteToString(v) | |
}) | |
return queries | |
} | |
func extractParams(ctx fiber.Ctx) map[string]string { | |
params := lawang.MapStringPool.Get() | |
ctx.Bind().URI(params) | |
return params | |
} | |
func resolveTimeout(endpoint *configs.Endpoint) int { | |
if endpoint.RequestTimeout > 0 { | |
return int(endpoint.RequestTimeout) | |
} | |
return configs.Config.RequestTimeout | |
} | |
func parseBody(ctx fiber.Ctx) []byte { | |
if ctx.Method() != fiber.MethodPost && ctx.Method() != fiber.MethodPut && ctx.Method() != fiber.MethodPatch { | |
return nil | |
} | |
bodyMap := jsons.NewCachableMap[string]() | |
var bodyBytes []byte | |
switch bytes.ByteToString(ctx.Request().Header.ContentType()) { | |
case configs.LAWANG_CONTENT_TYPE_URL_ENCODED: | |
urlEncoded, err := url.ParseQuery(bytes.ByteToString(ctx.Body())) | |
if err != nil { | |
return bodyBytes | |
} | |
for k, v := range urlEncoded { | |
bodyMap.Set(k, v[0]) | |
} | |
bodyBytes, _ = jsons.Marshal(bodyMap.Data()) | |
return bodyBytes | |
case configs.LAWANG_CONTENT_TYPE_JSON: | |
return ctx.Body() | |
default: | |
body := bodyMap.Data() | |
err := ctx.Bind().Body(&body) | |
if err != nil { | |
return ctx.Body() | |
} | |
bodyBytes, _ = jsons.Marshal(body) | |
return bodyBytes | |
} | |
} | |
func parseFormData(ctx fiber.Ctx, endpoint *configs.Endpoint) map[string]*File { | |
if ctx.Method() != fiber.MethodPost && ctx.Method() != fiber.MethodPut && ctx.Method() != fiber.MethodPatch { | |
return nil | |
} | |
if !strings.HasPrefix(bytes.ByteToString(ctx.Request().Header.Peek(configs.LAWANG_CONTENT_TYPE_HEADER)), configs.LAWANG_CONTENT_TYPE_FORM_DATA) { | |
return nil | |
} | |
if endpoint.Backend.Type != configs.LAWANG_JAVASCRIPT_SERVICE && endpoint.Backend.Type != configs.LAWANG_HTTP_SERVICE { | |
return nil | |
} | |
multipartForm, err := ctx.MultipartForm() | |
if err != nil { | |
return nil | |
} | |
files := make(map[string]*File, len(multipartForm.File)) | |
buffer := bytes.BufferPool.Get() | |
defer bytes.BufferPool.Put(buffer) | |
for k, v := range multipartForm.File { | |
f, err := v[0].Open() | |
if err != nil { | |
continue | |
} | |
buffer.Reset() | |
if _, err = io.Copy(buffer, f); err == nil { | |
file := FilePool.Get() | |
file.Name = v[0].Filename | |
file.Ext = filepath.Ext(file.Name) | |
file.Content = buffer.Bytes() | |
files[k] = file | |
} | |
f.Close() | |
} | |
return files | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment