mirror of
https://github.com/eolinker/apinto
synced 2025-10-04 16:32:44 +08:00
httpCtx 副本包
This commit is contained in:
@@ -3,6 +3,7 @@ package http_context
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
http_context_copy "github.com/eolinker/apinto/node/http-context/http-context-copy"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -189,41 +190,17 @@ func (ctx *HttpContext) Clone() (eoscContext.EoContext, error) {
|
|||||||
return nil, fmt.Errorf("%s %w", "HttpContext", eoscContext.ErrEoCtxUnCloneable)
|
return nil, fmt.Errorf("%s %w", "HttpContext", eoscContext.ErrEoCtxUnCloneable)
|
||||||
}
|
}
|
||||||
|
|
||||||
cloneCtx := pool.Get().(*HttpContext)
|
ctxCopy := http_context_copy.NewContextCopy(ctx.fastHttpRequestCtx, ctx.requestID, ctx.port, ctx.labels)
|
||||||
remoteAddr := ctx.fastHttpRequestCtx.RemoteAddr().String()
|
|
||||||
|
|
||||||
cloneReq := fasthttp.AcquireRequest()
|
ctxCopy.SetCompleteHandler(ctx.completeHandler)
|
||||||
ctx.proxyRequest.Request().CopyTo(cloneReq)
|
ctxCopy.SetFinish(ctx.finishHandler)
|
||||||
cloneResp := fasthttp.AcquireResponse()
|
ctxCopy.SetUpstreamHostHandler(ctx.upstreamHostHandler)
|
||||||
ctx.response.Response.CopyTo(cloneResp)
|
ctxCopy.SetApp(ctx.app)
|
||||||
|
ctxCopy.SetBalance(ctx.balance)
|
||||||
|
|
||||||
//cloneRequestCtx := new(fasthttp.RequestCtx)
|
//Ctx set retry,timeout TODO
|
||||||
//cloneRequestCtx.Request = *cloneReq
|
|
||||||
//cloneRequestCtx.Response = *cloneResp
|
|
||||||
cloneCtx.fastHttpRequestCtx = ctx.fastHttpRequestCtx //TODO
|
|
||||||
|
|
||||||
cloneCtx.requestID = ctx.requestID //TODO
|
return ctxCopy, nil
|
||||||
cloneCtx.requestReader.reset(cloneReq, remoteAddr)
|
|
||||||
cloneCtx.proxyRequest.reset(cloneReq, remoteAddr)
|
|
||||||
cloneCtx.proxyRequests = cloneCtx.proxyRequests[:0]
|
|
||||||
cloneCtx.response.reset(cloneResp)
|
|
||||||
|
|
||||||
cloneCtx.port = ctx.port
|
|
||||||
cloneCtx.ctx = ctx.ctx
|
|
||||||
|
|
||||||
cloneCtx.completeHandler = ctx.completeHandler
|
|
||||||
cloneCtx.finishHandler = ctx.finishHandler
|
|
||||||
cloneCtx.upstreamHostHandler = ctx.upstreamHostHandler
|
|
||||||
cloneCtx.app = ctx.app
|
|
||||||
cloneCtx.balance = ctx.balance
|
|
||||||
|
|
||||||
cLabels := make(map[string]string, len(ctx.labels))
|
|
||||||
for k, v := range ctx.labels {
|
|
||||||
cLabels[k] = v
|
|
||||||
}
|
|
||||||
cloneCtx.labels = cLabels
|
|
||||||
|
|
||||||
return cloneCtx, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext 创建Context
|
// NewContext 创建Context
|
||||||
|
293
node/http-context/http-context-copy/body.go
Normal file
293
node/http-context/http-context-copy/body.go
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
http_context "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"mime"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||||
|
var (
|
||||||
|
_ http_context.IBodyDataWriter = (*BodyRequestHandler)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MultipartForm = "multipart/form-data"
|
||||||
|
FormData = "application/x-www-form-urlencoded"
|
||||||
|
TEXT = "text/plain"
|
||||||
|
JSON = "application/json"
|
||||||
|
JavaScript = "application/javascript"
|
||||||
|
AppLicationXML = "application/xml"
|
||||||
|
TextXML = "text/xml"
|
||||||
|
Html = "text/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BodyRequestHandler body请求处理器
|
||||||
|
type BodyRequestHandler struct {
|
||||||
|
request *fasthttp.Request
|
||||||
|
|
||||||
|
formdata *multipart.Form
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyRequestHandler) MultipartForm() (*multipart.Form, error) {
|
||||||
|
if b.formdata != nil {
|
||||||
|
return b.formdata, nil
|
||||||
|
}
|
||||||
|
if !strings.Contains(b.ContentType(), MultipartForm) {
|
||||||
|
return nil, ErrorNotMultipart
|
||||||
|
}
|
||||||
|
form, err := b.request.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.formdata = &multipart.Form{
|
||||||
|
Value: form.Value,
|
||||||
|
File: form.File,
|
||||||
|
}
|
||||||
|
b.resetFile()
|
||||||
|
return form, nil
|
||||||
|
}
|
||||||
|
func (b *BodyRequestHandler) Files() (map[string][]*multipart.FileHeader, error) {
|
||||||
|
form, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return form.File, nil
|
||||||
|
}
|
||||||
|
func (b *BodyRequestHandler) reset(request *fasthttp.Request) {
|
||||||
|
b.request = request
|
||||||
|
b.formdata = nil
|
||||||
|
}
|
||||||
|
func NewBodyRequestHandler(request *fasthttp.Request) *BodyRequestHandler {
|
||||||
|
return &BodyRequestHandler{request: request}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForm 获取表单参数
|
||||||
|
func (b *BodyRequestHandler) GetForm(key string) string {
|
||||||
|
contentType, _, _ := mime.ParseMediaType(b.ContentType())
|
||||||
|
|
||||||
|
switch contentType {
|
||||||
|
case FormData:
|
||||||
|
args := b.request.PostArgs()
|
||||||
|
if args == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(args.Peek(key))
|
||||||
|
case MultipartForm:
|
||||||
|
form, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
vs := form.Value[key]
|
||||||
|
if len(vs) > 0 {
|
||||||
|
return vs[0]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentType 获取contentType
|
||||||
|
func (b *BodyRequestHandler) ContentType() string {
|
||||||
|
return string(b.request.Header.ContentType())
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyForm 获取表单参数
|
||||||
|
func (b *BodyRequestHandler) BodyForm() (url.Values, error) {
|
||||||
|
|
||||||
|
contentType, _, _ := mime.ParseMediaType(string(b.request.Header.ContentType()))
|
||||||
|
switch contentType {
|
||||||
|
case FormData:
|
||||||
|
return url.ParseQuery(string(b.request.Body()))
|
||||||
|
case MultipartForm:
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return multipartForm.Value, nil
|
||||||
|
default:
|
||||||
|
return nil, ErrorNotForm
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawBody 获取raw数据
|
||||||
|
func (b *BodyRequestHandler) RawBody() ([]byte, error) {
|
||||||
|
return b.request.Body(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyRequestHandler) GetFile(key string) ([]*multipart.FileHeader, bool) {
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
fl, has := multipartForm.File[key]
|
||||||
|
|
||||||
|
return fl, has
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyRequestHandler) SetToForm(key, value string) error {
|
||||||
|
contentType, _, _ := mime.ParseMediaType(string(b.request.Header.ContentType()))
|
||||||
|
switch contentType {
|
||||||
|
case FormData:
|
||||||
|
b.request.PostArgs().Set(key, value)
|
||||||
|
b.request.SetBodyRaw(b.request.PostArgs().QueryString())
|
||||||
|
return nil
|
||||||
|
case MultipartForm:
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
multipartForm.Value[key] = []string{value}
|
||||||
|
return b.resetFile()
|
||||||
|
default:
|
||||||
|
return ErrorNotForm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddForm 新增表单参数
|
||||||
|
func (b *BodyRequestHandler) AddForm(key, value string) error {
|
||||||
|
|
||||||
|
contentType, _, _ := mime.ParseMediaType(string(b.request.Header.ContentType()))
|
||||||
|
switch contentType {
|
||||||
|
case FormData:
|
||||||
|
b.request.PostArgs().Add(key, value)
|
||||||
|
b.request.SetBody(b.request.PostArgs().QueryString())
|
||||||
|
return nil
|
||||||
|
case MultipartForm:
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
multipartForm.Value[key] = append(multipartForm.Value[key], value)
|
||||||
|
return b.resetFile()
|
||||||
|
default:
|
||||||
|
return ErrorNotForm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFile 新增文件参数
|
||||||
|
func (b *BodyRequestHandler) AddFile(key string, file *multipart.FileHeader) error {
|
||||||
|
|
||||||
|
contentType, _, _ := mime.ParseMediaType(b.ContentType())
|
||||||
|
if contentType != FormData && contentType != MultipartForm {
|
||||||
|
return ErrorNotMultipart
|
||||||
|
}
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
multipartForm.File[key] = append(multipartForm.File[key], file)
|
||||||
|
|
||||||
|
return b.resetFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFile 设置文件参数
|
||||||
|
func (b *BodyRequestHandler) SetFile(files map[string][]*multipart.FileHeader) error {
|
||||||
|
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
multipartForm.File = files
|
||||||
|
|
||||||
|
return b.resetFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BodyRequestHandler) resetFile() error {
|
||||||
|
multipartForm := b.formdata
|
||||||
|
if multipartForm == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := new(bytes.Buffer)
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
|
||||||
|
for name, fs := range multipartForm.File {
|
||||||
|
for _, f := range fs {
|
||||||
|
fio, err := f.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
part, err := writer.CreateFormFile(name, f.Filename)
|
||||||
|
if err != nil {
|
||||||
|
fio.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(fio)
|
||||||
|
if err != nil {
|
||||||
|
fio.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = part.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
fio.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fio.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, values := range multipartForm.Value {
|
||||||
|
//temp := make(url.Values)
|
||||||
|
//temp[key] = values
|
||||||
|
//value := temp.Encode()
|
||||||
|
for _, value := range values {
|
||||||
|
err := writer.WriteField(key, value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
err := writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.request.Header.SetContentType(writer.FormDataContentType())
|
||||||
|
b.request.SetBodyRaw(body.Bytes())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetForm 设置表单参数
|
||||||
|
func (b *BodyRequestHandler) SetForm(values url.Values) error {
|
||||||
|
|
||||||
|
contentType, _, _ := mime.ParseMediaType(b.ContentType())
|
||||||
|
if contentType != FormData && contentType != MultipartForm {
|
||||||
|
return ErrorNotForm
|
||||||
|
}
|
||||||
|
switch contentType {
|
||||||
|
case FormData:
|
||||||
|
b.request.SetBodyString(values.Encode())
|
||||||
|
case MultipartForm:
|
||||||
|
multipartForm, err := b.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
multipartForm.Value = values
|
||||||
|
return b.resetFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorNotForm
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRaw 设置raw数据
|
||||||
|
func (b *BodyRequestHandler) SetRaw(contentType string, body []byte) {
|
||||||
|
b.request.SetBodyRaw(body)
|
||||||
|
b.request.Header.SetContentType(contentType)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
266
node/http-context/http-context-copy/context.go
Normal file
266
node/http-context/http-context-copy/context.go
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/eolinker/eosc/utils/config"
|
||||||
|
|
||||||
|
fasthttp_client "github.com/eolinker/apinto/node/fasthttp-client"
|
||||||
|
|
||||||
|
eoscContext "github.com/eolinker/eosc/eocontext"
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IHttpContext = (*HttpContextCopy)(nil)
|
||||||
|
|
||||||
|
// HttpContextCopy fasthttpRequestCtx
|
||||||
|
type HttpContextCopy struct {
|
||||||
|
proxyRequest ProxyRequest
|
||||||
|
proxyRequests []http_service.IProxy
|
||||||
|
requestID string
|
||||||
|
response Response
|
||||||
|
requestReader RequestReader
|
||||||
|
ctx context.Context
|
||||||
|
completeHandler eoscContext.CompleteHandler
|
||||||
|
finishHandler eoscContext.FinishHandler
|
||||||
|
app eoscContext.EoApp
|
||||||
|
balance eoscContext.BalanceHandler
|
||||||
|
upstreamHostHandler eoscContext.UpstreamHostHandler
|
||||||
|
labels map[string]string
|
||||||
|
port int
|
||||||
|
|
||||||
|
localIP net.IP
|
||||||
|
netAddr net.Addr
|
||||||
|
acceptTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) GetUpstreamHostHandler() eoscContext.UpstreamHostHandler {
|
||||||
|
return ctx.upstreamHostHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SetUpstreamHostHandler(handler eoscContext.UpstreamHostHandler) {
|
||||||
|
ctx.upstreamHostHandler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) LocalIP() net.IP {
|
||||||
|
return ctx.localIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) LocalAddr() net.Addr {
|
||||||
|
return ctx.netAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) LocalPort() int {
|
||||||
|
return ctx.port
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) GetApp() eoscContext.EoApp {
|
||||||
|
return ctx.app
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SetApp(app eoscContext.EoApp) {
|
||||||
|
ctx.app = app
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) GetBalance() eoscContext.BalanceHandler {
|
||||||
|
return ctx.balance
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SetBalance(handler eoscContext.BalanceHandler) {
|
||||||
|
ctx.balance = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SetLabel(name, value string) {
|
||||||
|
ctx.labels[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) GetLabel(name string) string {
|
||||||
|
return ctx.labels[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Labels() map[string]string {
|
||||||
|
return ctx.labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) GetComplete() eoscContext.CompleteHandler {
|
||||||
|
return ctx.completeHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SetCompleteHandler(handler eoscContext.CompleteHandler) {
|
||||||
|
ctx.completeHandler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) GetFinish() eoscContext.FinishHandler {
|
||||||
|
return ctx.finishHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SetFinish(handler eoscContext.FinishHandler) {
|
||||||
|
ctx.finishHandler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Scheme() string {
|
||||||
|
return string(ctx.requestReader.req.URI().Scheme())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Assert(i interface{}) error {
|
||||||
|
if v, ok := i.(*http_service.IHttpContext); ok {
|
||||||
|
*v = ctx
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("not suport:%s", config.TypeNameOf(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Proxies() []http_service.IProxy {
|
||||||
|
return ctx.proxyRequests
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Response() http_service.IResponse {
|
||||||
|
return &ctx.response
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) SendTo(address string, timeout time.Duration) error {
|
||||||
|
|
||||||
|
scheme, host := readAddress(address)
|
||||||
|
request := ctx.proxyRequest.Request()
|
||||||
|
|
||||||
|
passHost, targetHost := ctx.GetUpstreamHostHandler().PassHost()
|
||||||
|
switch passHost {
|
||||||
|
case eoscContext.PassHost:
|
||||||
|
case eoscContext.NodeHost:
|
||||||
|
request.URI().SetHost(host)
|
||||||
|
case eoscContext.ReWriteHost:
|
||||||
|
request.URI().SetHost(targetHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
beginTime := time.Now()
|
||||||
|
ctx.response.responseError = fasthttp_client.ProxyTimeout(address, request, ctx.response.Response, timeout)
|
||||||
|
agent := newRequestAgent(&ctx.proxyRequest, host, scheme, beginTime, time.Now())
|
||||||
|
if ctx.response.responseError != nil {
|
||||||
|
agent.setStatusCode(504)
|
||||||
|
} else {
|
||||||
|
agent.setStatusCode(ctx.response.Response.StatusCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.setResponseLength(ctx.response.Response.Header.ContentLength())
|
||||||
|
|
||||||
|
ctx.proxyRequests = append(ctx.proxyRequests, agent)
|
||||||
|
return ctx.response.responseError
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Context() context.Context {
|
||||||
|
if ctx.ctx == nil {
|
||||||
|
|
||||||
|
ctx.ctx = context.Background()
|
||||||
|
}
|
||||||
|
return ctx.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) AcceptTime() time.Time {
|
||||||
|
return ctx.acceptTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Value(key interface{}) interface{} {
|
||||||
|
return ctx.Context().Value(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) WithValue(key, val interface{}) {
|
||||||
|
ctx.ctx = context.WithValue(ctx.Context(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Proxy() http_service.IRequest {
|
||||||
|
return &ctx.proxyRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Request() http_service.IRequestReader {
|
||||||
|
|
||||||
|
return &ctx.requestReader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) IsCloneable() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *HttpContextCopy) Clone() (eoscContext.EoContext, error) {
|
||||||
|
return nil, fmt.Errorf("%s %w", "HttpContextCopy", eoscContext.ErrEoCtxUnCloneable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContextCopy 创建Context-Copy
|
||||||
|
func NewContextCopy(requestCtx *fasthttp.RequestCtx, requestID string, port int, labels map[string]string) *HttpContextCopy {
|
||||||
|
ctxCopy := pool.Get().(*HttpContextCopy)
|
||||||
|
remoteAddr := requestCtx.RemoteAddr().String()
|
||||||
|
|
||||||
|
cloneReq := fasthttp.AcquireRequest()
|
||||||
|
requestCtx.Request.CopyTo(cloneReq)
|
||||||
|
cloneResp := fasthttp.AcquireResponse()
|
||||||
|
requestCtx.Response.CopyTo(cloneResp)
|
||||||
|
|
||||||
|
ctxCopy.requestReader.reset(cloneReq, remoteAddr)
|
||||||
|
ctxCopy.proxyRequest.reset(cloneReq, remoteAddr)
|
||||||
|
ctxCopy.proxyRequests = ctxCopy.proxyRequests[:0]
|
||||||
|
ctxCopy.response.reset(cloneResp)
|
||||||
|
|
||||||
|
ctxCopy.localIP = requestCtx.LocalIP()
|
||||||
|
ctxCopy.netAddr = requestCtx.LocalAddr()
|
||||||
|
ctxCopy.acceptTime = requestCtx.Time()
|
||||||
|
|
||||||
|
ctxCopy.requestID = requestID
|
||||||
|
ctxCopy.port = port
|
||||||
|
|
||||||
|
ctxCopy.ctx = context.Background()
|
||||||
|
ctxCopy.WithValue("request_time", ctxCopy.acceptTime)
|
||||||
|
|
||||||
|
cLabels := make(map[string]string, len(labels))
|
||||||
|
for k, v := range labels {
|
||||||
|
cLabels[k] = v
|
||||||
|
}
|
||||||
|
ctxCopy.labels = cLabels
|
||||||
|
|
||||||
|
return ctxCopy
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestId 请求ID
|
||||||
|
func (ctx *HttpContextCopy) RequestId() string {
|
||||||
|
return ctx.requestID
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastFinish finish
|
||||||
|
func (ctx *HttpContextCopy) FastFinish() {
|
||||||
|
if ctx.response.responseError != nil {
|
||||||
|
ctx.response.Response.SetStatusCode(504)
|
||||||
|
ctx.response.Response.SetBodyString(ctx.response.responseError.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.port = 0
|
||||||
|
ctx.ctx = nil
|
||||||
|
ctx.app = nil
|
||||||
|
ctx.balance = nil
|
||||||
|
ctx.upstreamHostHandler = nil
|
||||||
|
ctx.finishHandler = nil
|
||||||
|
ctx.completeHandler = nil
|
||||||
|
|
||||||
|
ctx.requestReader.Finish()
|
||||||
|
ctx.proxyRequest.Finish()
|
||||||
|
ctx.response.Finish()
|
||||||
|
pool.Put(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NotFound(ctx *HttpContextCopy) {
|
||||||
|
ctx.response.Response.SetStatusCode(404)
|
||||||
|
ctx.response.Response.SetBody([]byte("404 Not Found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAddress(addr string) (scheme, host string) {
|
||||||
|
if i := strings.Index(addr, "://"); i > 0 {
|
||||||
|
return strings.ToLower(addr[:i]), addr[i+3:]
|
||||||
|
}
|
||||||
|
return "http", addr
|
||||||
|
}
|
10
node/http-context/http-context-copy/error.go
Normal file
10
node/http-context/http-context-copy/error.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorNotForm = errors.New("contentType is not Form")
|
||||||
|
ErrorNotMultipart = errors.New("contentType is not Multipart")
|
||||||
|
ErrorNotAllowRaw = errors.New("contentType is not allow Raw")
|
||||||
|
ErrorNotSend = errors.New("not send")
|
||||||
|
)
|
140
node/http-context/http-context-copy/header.go
Normal file
140
node/http-context/http-context-copy/header.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IHeaderWriter = (*RequestHeader)(nil)
|
||||||
|
|
||||||
|
type RequestHeader struct {
|
||||||
|
header *fasthttp.RequestHeader
|
||||||
|
tmp http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) RawHeader() string {
|
||||||
|
return h.header.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) reset(header *fasthttp.RequestHeader) {
|
||||||
|
h.header = header
|
||||||
|
h.tmp = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) initHeader() {
|
||||||
|
if h.tmp == nil {
|
||||||
|
h.tmp = make(http.Header)
|
||||||
|
h.header.VisitAll(func(key, value []byte) {
|
||||||
|
bytes.SplitN(value, []byte(":"), 2)
|
||||||
|
h.tmp[string(key)] = []string{string(value)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) Host() string {
|
||||||
|
return string(h.header.Host())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) GetHeader(name string) string {
|
||||||
|
return h.Headers().Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) Headers() http.Header {
|
||||||
|
h.initHeader()
|
||||||
|
return h.tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) SetHeader(key, value string) {
|
||||||
|
if h.tmp != nil {
|
||||||
|
h.tmp.Set(key, value)
|
||||||
|
}
|
||||||
|
h.header.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) AddHeader(key, value string) {
|
||||||
|
if h.tmp != nil {
|
||||||
|
h.tmp.Add(key, value)
|
||||||
|
}
|
||||||
|
h.header.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) DelHeader(key string) {
|
||||||
|
if h.tmp != nil {
|
||||||
|
h.tmp.Del(key)
|
||||||
|
}
|
||||||
|
h.header.Del(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) SetHost(host string) {
|
||||||
|
if h.tmp != nil {
|
||||||
|
h.tmp.Set("Host", host)
|
||||||
|
}
|
||||||
|
h.header.SetHost(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseHeader struct {
|
||||||
|
header *fasthttp.ResponseHeader
|
||||||
|
tmp http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseHeader) reset(header *fasthttp.ResponseHeader) {
|
||||||
|
r.header = header
|
||||||
|
r.tmp = nil
|
||||||
|
}
|
||||||
|
func NewResponseHeader(header *fasthttp.ResponseHeader) *ResponseHeader {
|
||||||
|
return &ResponseHeader{header: header}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseHeader) GetHeader(name string) string {
|
||||||
|
return r.Headers().Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseHeader) Headers() http.Header {
|
||||||
|
|
||||||
|
if r.tmp == nil {
|
||||||
|
r.tmp = make(http.Header)
|
||||||
|
hs := strings.Split(r.header.String(), "\r\n")
|
||||||
|
for _, t := range hs {
|
||||||
|
vs := strings.Split(t, ":")
|
||||||
|
if len(vs) < 2 {
|
||||||
|
if vs[0] == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.tmp[vs[0]] = []string{""}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.tmp[vs[0]] = []string{strings.TrimSpace(vs[1])}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseHeader) SetHeader(key, value string) {
|
||||||
|
if r.tmp != nil {
|
||||||
|
r.tmp.Set(key, value)
|
||||||
|
}
|
||||||
|
r.header.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseHeader) AddHeader(key, value string) {
|
||||||
|
if r.tmp != nil {
|
||||||
|
r.tmp.Add(key, value)
|
||||||
|
}
|
||||||
|
r.header.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResponseHeader) DelHeader(key string) {
|
||||||
|
if r.tmp != nil {
|
||||||
|
r.tmp.Del(key)
|
||||||
|
}
|
||||||
|
r.header.Del(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) GetCookie(key string) string {
|
||||||
|
return string(h.header.Cookie(key))
|
||||||
|
}
|
19
node/http-context/http-context-copy/pool.go
Normal file
19
node/http-context/http-context-copy/pool.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pool = sync.Pool{
|
||||||
|
New: newContext,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func newContext() interface{} {
|
||||||
|
h := new(HttpContextCopy)
|
||||||
|
h.proxyRequests = make([]http_service.IProxy, 0, 5)
|
||||||
|
return h
|
||||||
|
}
|
89
node/http-context/http-context-copy/proxy-agent.go
Normal file
89
node/http-context/http-context-copy/proxy-agent.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IProxy = (*requestAgent)(nil)
|
||||||
|
|
||||||
|
type requestAgent struct {
|
||||||
|
http_service.IRequest
|
||||||
|
host string
|
||||||
|
scheme string
|
||||||
|
statusCode int
|
||||||
|
status string
|
||||||
|
responseLength int
|
||||||
|
beginTime time.Time
|
||||||
|
endTime time.Time
|
||||||
|
hostAgent *UrlAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) ProxyTime() time.Time {
|
||||||
|
return a.beginTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) StatusCode() int {
|
||||||
|
return a.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) Status() string {
|
||||||
|
return a.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) setStatusCode(code int) {
|
||||||
|
a.statusCode = code
|
||||||
|
a.status = strconv.Itoa(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) ResponseLength() int {
|
||||||
|
return a.responseLength
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) setResponseLength(length int) {
|
||||||
|
if length > 0 {
|
||||||
|
a.responseLength = length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRequestAgent(IRequest http_service.IRequest, host string, scheme string, beginTime, endTime time.Time) *requestAgent {
|
||||||
|
return &requestAgent{IRequest: IRequest, host: host, scheme: scheme, beginTime: beginTime, endTime: endTime}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) ResponseTime() int64 {
|
||||||
|
return a.endTime.Sub(a.beginTime).Milliseconds()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *requestAgent) URI() http_service.IURIWriter {
|
||||||
|
if a.hostAgent == nil {
|
||||||
|
a.hostAgent = NewUrlAgent(a.IRequest.URI(), a.host, a.scheme)
|
||||||
|
}
|
||||||
|
return a.hostAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
type UrlAgent struct {
|
||||||
|
http_service.IURIWriter
|
||||||
|
host string
|
||||||
|
scheme string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UrlAgent) SetScheme(scheme string) {
|
||||||
|
u.scheme = scheme
|
||||||
|
}
|
||||||
|
func (u *UrlAgent) Scheme() string {
|
||||||
|
return u.scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UrlAgent) Host() string {
|
||||||
|
return u.host
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UrlAgent) SetHost(host string) {
|
||||||
|
u.host = host
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUrlAgent(IURIWriter http_service.IURIWriter, host string, scheme string) *UrlAgent {
|
||||||
|
return &UrlAgent{IURIWriter: IURIWriter, host: host, scheme: scheme}
|
||||||
|
}
|
72
node/http-context/http-context-copy/proxy.go
Normal file
72
node/http-context/http-context-copy/proxy.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IRequest = (*ProxyRequest)(nil)
|
||||||
|
|
||||||
|
type ProxyRequest struct {
|
||||||
|
RequestReader
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (r *ProxyRequest) clone() *ProxyRequest {
|
||||||
|
// return NewProxyRequest(r.Request(), r.remoteAddr)
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (r *ProxyRequest) Finish() error {
|
||||||
|
fasthttp.ReleaseRequest(r.req)
|
||||||
|
r.RequestReader.Finish()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (r *ProxyRequest) Header() http_service.IHeaderWriter {
|
||||||
|
return &r.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProxyRequest) Body() http_service.IBodyDataWriter {
|
||||||
|
return &r.body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProxyRequest) URI() http_service.IURIWriter {
|
||||||
|
return &r.uri
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
xforwardedforKey = []byte("x-forwarded-for")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *ProxyRequest) reset(request *fasthttp.Request, remoteAddr string) {
|
||||||
|
proxyRequest := fasthttp.AcquireRequest()
|
||||||
|
request.CopyTo(proxyRequest)
|
||||||
|
|
||||||
|
forwardedFor := proxyRequest.Header.PeekBytes(xforwardedforKey)
|
||||||
|
if len(forwardedFor) > 0 {
|
||||||
|
if i := bytes.IndexByte(forwardedFor, ','); i > 0 {
|
||||||
|
r.realIP = string(forwardedFor[:i])
|
||||||
|
} else {
|
||||||
|
r.realIP = string(forwardedFor)
|
||||||
|
}
|
||||||
|
proxyRequest.Header.Set("x-forwarded-for", fmt.Sprint(string(forwardedFor), ",", r.remoteAddr))
|
||||||
|
} else {
|
||||||
|
proxyRequest.Header.Set("x-forwarded-for", r.remoteAddr)
|
||||||
|
r.realIP = r.remoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
r.RequestReader.reset(proxyRequest, remoteAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//func NewProxyRequest(request *fasthttp.Request, remoteAddr string) *ProxyRequest {
|
||||||
|
// proxyRequest := fasthttp.AcquireRequest()
|
||||||
|
// request.CopyTo(proxyRequest)
|
||||||
|
// return &ProxyRequest{
|
||||||
|
// RequestReader: NewRequestReader(proxyRequest, remoteAddr),
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (r *ProxyRequest) SetMethod(s string) {
|
||||||
|
r.Request().Header.SetMethod(s)
|
||||||
|
}
|
104
node/http-context/http-context-copy/request-reader.go
Normal file
104
node/http-context/http-context-copy/request-reader.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IRequestReader = (*RequestReader)(nil)
|
||||||
|
|
||||||
|
type RequestReader struct {
|
||||||
|
body BodyRequestHandler
|
||||||
|
req *fasthttp.Request
|
||||||
|
headers RequestHeader
|
||||||
|
uri URIRequest
|
||||||
|
remoteAddr string
|
||||||
|
remotePort string
|
||||||
|
realIP string
|
||||||
|
length int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) ContentLength() int {
|
||||||
|
return r.length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) ContentType() string {
|
||||||
|
return string(r.req.Header.ContentType())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) String() string {
|
||||||
|
return r.req.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) Method() string {
|
||||||
|
return string(r.req.Header.Method())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) Header() http_service.IHeaderReader {
|
||||||
|
return &r.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) Body() http_service.IBodyDataReader {
|
||||||
|
return &r.body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) URI() http_service.IURIReader {
|
||||||
|
return &r.uri
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) ReadIP() string {
|
||||||
|
if r.realIP == "" {
|
||||||
|
realIP := r.headers.GetHeader("x-real-ip")
|
||||||
|
if realIP == "" {
|
||||||
|
realIP = r.remoteAddr
|
||||||
|
}
|
||||||
|
r.realIP = realIP
|
||||||
|
}
|
||||||
|
return r.realIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) ForwardIP() string {
|
||||||
|
return r.headers.GetHeader("x-forwarded-for")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) RemoteAddr() string {
|
||||||
|
return r.remoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) RemotePort() string {
|
||||||
|
return r.remotePort
|
||||||
|
}
|
||||||
|
func (r *RequestReader) Finish() error {
|
||||||
|
r.req = nil
|
||||||
|
r.body.reset(nil)
|
||||||
|
r.headers.reset(nil)
|
||||||
|
r.uri.reset(nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (r *RequestReader) reset(req *fasthttp.Request, remoteAddr string) {
|
||||||
|
r.req = req
|
||||||
|
r.remoteAddr = remoteAddr
|
||||||
|
|
||||||
|
r.body.reset(req)
|
||||||
|
|
||||||
|
r.headers.reset(&req.Header)
|
||||||
|
r.uri.uri = req.URI()
|
||||||
|
|
||||||
|
idx := strings.LastIndex(remoteAddr, ":")
|
||||||
|
if idx != -1 {
|
||||||
|
r.remoteAddr = remoteAddr[:idx]
|
||||||
|
r.remotePort = remoteAddr[idx+1:]
|
||||||
|
}
|
||||||
|
length := r.req.Header.ContentLength()
|
||||||
|
if length > 0 {
|
||||||
|
r.length = length
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestReader) Request() *fasthttp.Request {
|
||||||
|
return r.req
|
||||||
|
}
|
121
node/http-context/http-context-copy/response.go
Normal file
121
node/http-context/http-context-copy/response.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IResponse = (*Response)(nil)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
ResponseHeader
|
||||||
|
*fasthttp.Response
|
||||||
|
length int
|
||||||
|
responseTime time.Duration
|
||||||
|
proxyStatusCode int
|
||||||
|
responseError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) ContentLength() int {
|
||||||
|
if r.length == 0 {
|
||||||
|
return r.Response.Header.ContentLength()
|
||||||
|
}
|
||||||
|
return r.length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) ContentType() string {
|
||||||
|
return string(r.Response.Header.ContentType())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) HeadersString() string {
|
||||||
|
return r.header.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) ResponseError() error {
|
||||||
|
return r.responseError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) ClearError() {
|
||||||
|
r.responseError = nil
|
||||||
|
}
|
||||||
|
func (r *Response) Finish() error {
|
||||||
|
r.Response = nil
|
||||||
|
r.ResponseHeader.reset(nil)
|
||||||
|
r.responseError = nil
|
||||||
|
r.proxyStatusCode = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (r *Response) reset(resp *fasthttp.Response) {
|
||||||
|
r.Response = resp
|
||||||
|
r.ResponseHeader.reset(&resp.Header)
|
||||||
|
r.responseError = nil
|
||||||
|
r.proxyStatusCode = 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) BodyLen() int {
|
||||||
|
return r.header.ContentLength()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) GetBody() []byte {
|
||||||
|
if strings.Contains(r.GetHeader("Content-Encoding"), "gzip") {
|
||||||
|
body, _ := r.BodyGunzip()
|
||||||
|
r.DelHeader("Content-Encoding")
|
||||||
|
r.SetHeader("Content-Length", strconv.Itoa(len(body)))
|
||||||
|
r.Response.SetBody(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Response.Body()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) SetBody(bytes []byte) {
|
||||||
|
if strings.Contains(r.GetHeader("Content-Encoding"), "gzip") {
|
||||||
|
r.DelHeader("Content-Encoding")
|
||||||
|
}
|
||||||
|
r.Response.SetBody(bytes)
|
||||||
|
r.length = len(bytes)
|
||||||
|
r.SetHeader("Content-Length", strconv.Itoa(r.length))
|
||||||
|
r.responseError = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) StatusCode() int {
|
||||||
|
if r.responseError != nil {
|
||||||
|
return 504
|
||||||
|
}
|
||||||
|
return r.Response.StatusCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Status() string {
|
||||||
|
return strconv.Itoa(r.StatusCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) SetStatus(code int, status string) {
|
||||||
|
r.Response.SetStatusCode(code)
|
||||||
|
r.responseError = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原始的响应状态码
|
||||||
|
func (r *Response) ProxyStatusCode() int {
|
||||||
|
return r.proxyStatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) ProxyStatus() string {
|
||||||
|
return strconv.Itoa(r.proxyStatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) SetProxyStatus(code int, status string) {
|
||||||
|
r.proxyStatusCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) SetResponseTime(t time.Duration) {
|
||||||
|
r.responseTime = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) ResponseTime() time.Duration {
|
||||||
|
return r.responseTime
|
||||||
|
}
|
82
node/http-context/http-context-copy/uri.go
Normal file
82
node/http-context/http-context-copy/uri.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package http_context_copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ http_service.IURIWriter = (*URIRequest)(nil)
|
||||||
|
|
||||||
|
type URIRequest struct {
|
||||||
|
uri *fasthttp.URI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) reset(uri *fasthttp.URI) {
|
||||||
|
ur.uri = uri
|
||||||
|
}
|
||||||
|
func (ur *URIRequest) Path() string {
|
||||||
|
return string(ur.uri.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) SetScheme(scheme string) {
|
||||||
|
ur.uri.SetScheme(scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) Host() string {
|
||||||
|
return string(ur.uri.Host())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) SetQuery(key, value string) {
|
||||||
|
|
||||||
|
ur.uri.QueryArgs().Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) AddQuery(key, value string) {
|
||||||
|
ur.uri.QueryArgs().Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) DelQuery(key string) {
|
||||||
|
queryArgs := ur.uri.QueryArgs()
|
||||||
|
queryArgs.Del(key)
|
||||||
|
if queryArgs.Len() == 0 {
|
||||||
|
ur.uri.SetQueryStringBytes(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) SetRawQuery(raw string) {
|
||||||
|
ur.uri.SetQueryString(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewURIRequest(uri *fasthttp.URI) *URIRequest {
|
||||||
|
return &URIRequest{uri: uri}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) RequestURI() string {
|
||||||
|
return string(ur.uri.RequestURI())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) Scheme() string {
|
||||||
|
return string(ur.uri.Scheme())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) RawURL() string {
|
||||||
|
return string(ur.uri.FullURI())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) GetQuery(key string) string {
|
||||||
|
|
||||||
|
return string(ur.uri.QueryArgs().Peek(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) RawQuery() string {
|
||||||
|
return string(ur.uri.QueryString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) SetPath(s string) {
|
||||||
|
ur.uri.SetPath(s)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ur *URIRequest) SetHost(host string) {
|
||||||
|
ur.uri.SetHost(host)
|
||||||
|
}
|
Reference in New Issue
Block a user