diff --git a/checker/checker_test.go b/checker/checker_test.go index 169b0900..391c8f79 100644 --- a/checker/checker_test.go +++ b/checker/checker_test.go @@ -428,11 +428,11 @@ func TestCreateChecker(t *testing.T) { t.Run(tt.name, func(t *testing.T) { checker, err := http_service.Parse(tt.args.pattern) if (err != nil) != tt.wantErr { - t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("parse() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(checker, tt.want) { - t.Errorf("Parse() got = %v, want %v", checker, tt.want) + t.Errorf("parse() got = %v, want %v", checker, tt.want) } //验证check if checker != nil { diff --git a/drivers/auth/aksk/aksk_test.go b/drivers/auth/aksk/aksk_test.go index e527e75b..d72dec41 100644 --- a/drivers/auth/aksk/aksk_test.go +++ b/drivers/auth/aksk/aksk_test.go @@ -52,10 +52,10 @@ func createTestContext() { // http-service //request1, _ := http-service.NewRequest("GET", "http://www.demo.com/demo/login?parm1=value1&parm2=", &body{}) - //request1.Header.SetDriver("Authorization-Type", "ak/sk") - //request1.Header.SetDriver("Content-Type", "application/json") - //request1.Header.SetDriver("x-gateway-date", "20200605T104456Z") - //request1.Header.SetDriver("Authorization", "HMAC-SHA256 Access=4c897cfdfca60a59983adc2627942e7e, SignedHeaders=content-type;host;x-gateway-date, Signature=0c3d2598d931f36ca7d261d52dcd29f09d6573671bd593b7cbc55f73eb942758") + //request1.IHeader.SetDriver("Authorization-Type", "ak/sk") + //request1.IHeader.SetDriver("Content-Type", "application/json") + //request1.IHeader.SetDriver("x-gateway-date", "20200605T104456Z") + //request1.IHeader.SetDriver("Authorization", "HMAC-SHA256 Access=4c897cfdfca60a59983adc2627942e7e, SignedHeaders=content-type;host;x-gateway-date, Signature=0c3d2598d931f36ca7d261d52dcd29f09d6573671bd593b7cbc55f73eb942758") //Context1 := http_context.NewContext(request1, &writer{}) // fast http-service @@ -80,10 +80,10 @@ func createTestContext() { // http-service //request2, _ := http-service.NewRequest("GET", "http://www.demo.com/demo/login?parm1=value1&parm2=", &body{}) - //request2.Header.SetDriver("Authorization-Type", "ak/sk") - //request2.Header.SetDriver("Content-Type", "application/json") - //request2.Header.SetDriver("x-gateway-date", "20200605T104456Z") - //request2.Header.SetDriver("Authorization", "HMAC-SHA256 Access=4c897cfdfca60a59983adc2627942e7e, SignedHeaders=content-type;host;x-gateway-date, Signature=bb18110ddf327a9c1222a551527896d59cb854ca9084078cfa3a6eb23de3ddb8") + //request2.IHeader.SetDriver("Authorization-Type", "ak/sk") + //request2.IHeader.SetDriver("Content-Type", "application/json") + //request2.IHeader.SetDriver("x-gateway-date", "20200605T104456Z") + //request2.IHeader.SetDriver("Authorization", "HMAC-SHA256 Access=4c897cfdfca60a59983adc2627942e7e, SignedHeaders=content-type;host;x-gateway-date, Signature=bb18110ddf327a9c1222a551527896d59cb854ca9084078cfa3a6eb23de3ddb8") //Context2 := http_context.NewContext(request2, &writer{}) // https @@ -106,10 +106,10 @@ func createTestContext() { //传输了不存在的ak // http-service //request3, _ := http-service.NewRequest("GET", "http://www.demo.com/demo/login?parm1=value1&parm2=", &body{}) - //request3.Header.SetDriver("Authorization-Type", "ak/sk") - //request3.Header.SetDriver("Content-Type", "application/json") - //request3.Header.SetDriver("x-gateway-date", "20200605T104456Z") - //request3.Header.SetDriver("Authorization", "HMAC-SHA256 Access=dsaasdasda, SignedHeaders=content-type;host;x-gateway-date, Signature=0c3d2598d931f36ca7d261d52dcd29f09d6573671bd593b7cbc55f73eb942758") + //request3.IHeader.SetDriver("Authorization-Type", "ak/sk") + //request3.IHeader.SetDriver("Content-Type", "application/json") + //request3.IHeader.SetDriver("x-gateway-date", "20200605T104456Z") + //request3.IHeader.SetDriver("Authorization", "HMAC-SHA256 Access=dsaasdasda, SignedHeaders=content-type;host;x-gateway-date, Signature=0c3d2598d931f36ca7d261d52dcd29f09d6573671bd593b7cbc55f73eb942758") //Context3 := http_context.NewContext(request3, &writer{}) //testContexts = append(testContexts, Context3) diff --git a/drivers/auth/apikey/apikey.go b/drivers/auth/apikey/apikey.go index 832a9fc0..29529bff 100644 --- a/drivers/auth/apikey/apikey.go +++ b/drivers/auth/apikey/apikey.go @@ -81,7 +81,7 @@ func (a *apikey) getAuthValue(ctx http_service.IHttpContext) (string, error) { // 判断鉴权值是否在query if authorization := ctx.Request().URL().Query().Get("Apikey"); authorization != "" { if a.hideCredential { - ctx.Proxy().Querys().Del("Apikey") + ctx.Proxy().Queries().Del("Apikey") } return authorization, nil } diff --git a/drivers/auth/apikey/apikey_test.go b/drivers/auth/apikey/apikey_test.go index 1b9d88e7..4b1b9d66 100644 --- a/drivers/auth/apikey/apikey_test.go +++ b/drivers/auth/apikey/apikey_test.go @@ -231,7 +231,7 @@ func TestFormAuthorization(t *testing.T) { "Content-Type": "application/x-www-form-urlencoded", } // http-service - //req, err := buildRequest(headers, nil, formBody.Encode()) + //req, err := buildRequest(headers, nil, formBody.encode()) //if err != nil { // t.Error(err) // return diff --git a/drivers/auth/jwt/verify.go b/drivers/auth/jwt/verify.go index da34ae5d..54c55500 100644 --- a/drivers/auth/jwt/verify.go +++ b/drivers/auth/jwt/verify.go @@ -293,22 +293,22 @@ func decodeSegment(seg string) ([]byte, error) { return base64.URLEncoding.DecodeString(seg) } -// Encode JWT specific base64url encoding with padding stripped +// encode JWT specific base64url encoding with padding stripped func encodeSegment(seg []byte) string { return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") } -//ParseRSAPublicKeyFromPEM Parse PEM encoded PKCS1 or PKCS8 public key +//ParseRSAPublicKeyFromPEM parse PEM encoded PKCS1 or PKCS8 public key func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { var err error - // Parse PEM block + // parse PEM block var block *pem.Block if block, _ = pem.Decode(key); block == nil { return nil, errKeyMustBePEMEncoded } - // Parse the key + // parse the key var parsedKey interface{} if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil { @@ -327,17 +327,17 @@ func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { return pkey, nil } -//ParseECPublicKeyFromPEM Parse PEM encoded PKCS1 or PKCS8 public key +//ParseECPublicKeyFromPEM parse PEM encoded PKCS1 or PKCS8 public key func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) { var err error - // Parse PEM block + // parse PEM block var block *pem.Block if block, _ = pem.Decode(key); block == nil { return nil, errKeyMustBePEMEncoded } - // Parse the key + // parse the key var parsedKey interface{} if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil { @@ -520,7 +520,7 @@ func (j *jwt) retrieveJWTToken(context http_service.IHttpContext) (string, error if value := context.Request().URL().Query().Get(tokenName); value != "" { if j.hideCredentials { - context.Proxy().Querys().Del(tokenName) + context.Proxy().Queries().Del(tokenName) } return value, nil } diff --git a/drivers/service/service-http/service.go b/drivers/service/service-http/service.go index e6151910..b343deaf 100644 --- a/drivers/service/service-http/service.go +++ b/drivers/service/service-http/service.go @@ -120,7 +120,7 @@ func (s *serviceWorker) ProxyAddr() string { } //Handle 将服务发送到负载 -func (s *serviceWorker) Handle(ctx *http_context.Context, router service.IRouterEndpoint) error { +func (s *serviceWorker) Handle(ctx http_service.IHttpContext) error { // 构造context defer func() { if e := recover(); e != nil { diff --git a/filter/chain_test.go b/filter/chain_test.go index 23f6b17e..c0c6f664 100644 --- a/filter/chain_test.go +++ b/filter/chain_test.go @@ -117,11 +117,11 @@ func (t *TestContext) DelHeader(key string) { panic("implement me") } -func (t *TestContext) Set() http_service.Header { +func (t *TestContext) Set() http_service.IHeader { panic("implement me") } -func (t *TestContext) Append() http_service.Header { +func (t *TestContext) Append() http_service.IHeader { panic("implement me") } @@ -161,11 +161,11 @@ func (t *TestContext) RequestId() string { panic("implement me") } -func (t *TestContext) Request() http_service.RequestReader { +func (t *TestContext) Request() http_service.IRequestReader { panic("implement me") } -func (t *TestContext) Proxy() http_service.Request { +func (t *TestContext) Proxy() http_service.IRequest { panic("implement me") } @@ -173,7 +173,7 @@ func (t *TestContext) Labels() map[string]string { panic("implement me") } -func (t *TestContext) ProxyResponse() http_service.ResponseReader { +func (t *TestContext) ProxyResponse() http_service.IResponseReader { panic("implement me") } diff --git a/go.mod b/go.mod index 2935a23e..9b58be80 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.15 require ( github.com/eolinker/eosc v0.2.3 - github.com/eolinker/goku-standard-plugin v0.1.5 github.com/ghodss/yaml v1.0.0 github.com/go-basic/uuid v1.0.0 github.com/hashicorp/consul/api v1.9.1 diff --git a/node/http-context/body.go b/node/http-context/body.go index 8f558dea..fc675d86 100644 --- a/node/http-context/body.go +++ b/node/http-context/body.go @@ -6,7 +6,7 @@ import ( "encoding/xml" "errors" - goku_plugin "github.com/eolinker/goku-standard-plugin" + http_service "github.com/eolinker/eosc/http-service" "io/ioutil" "net/http" @@ -23,13 +23,24 @@ var ( errorNotAllowRaw = errors.New("contentType is not allow Raw") ) +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 { form url.Values rawBody []byte orgContentParam map[string]string contentType string - files map[string]*goku_plugin.FileHeader + files map[string]*http_service.FileHeader isInit bool isWriteRaw bool @@ -37,33 +48,83 @@ type BodyRequestHandler struct { object interface{} } -//Files 获取文件参数 -func (b *BodyRequestHandler) Files() (map[string]*goku_plugin.FileHeader, error) { +//GetForm 获取表单参数 +func (b *BodyRequestHandler) GetForm(key string) string { - err := b.Parse() + contentType, _, _ := mime.ParseMediaType(b.contentType) + if contentType != FormData && contentType != MultipartForm { + return "" + } + b.parse() + + if !b.isInit || b.form == nil { + return "" + } + return b.form.Get(key) +} + +//ContentType 获取contentType +func (b *BodyRequestHandler) ContentType() string { + return b.contentType +} + +//BodyForm 获取表单参数 +func (b *BodyRequestHandler) BodyForm() (url.Values, error) { + + err := b.parse() + if err != nil { + return nil, err + } + return b.form, nil +} + +//RawBody 获取raw数据 +func (b *BodyRequestHandler) RawBody() ([]byte, error) { + + err := b.encode() + if err != nil { + return nil, err + } + return b.rawBody, nil + +} + +//Files 获取文件参数 +func (b *BodyRequestHandler) Files() (map[string]*http_service.FileHeader, error) { + + err := b.parse() if err != nil { return nil, err } return b.files, nil - } -//Parse 解析 -func (b *BodyRequestHandler) Parse() error { +func (b *BodyRequestHandler) GetFile(key string) (file *http_service.FileHeader, has bool) { + err := b.parse() + + if err != nil { + return nil, false + } + file, has = b.files[key] + return file, has +} + +//parse 解析 +func (b *BodyRequestHandler) parse() error { if b.isInit { return nil } contentType, _, _ := mime.ParseMediaType(b.contentType) switch contentType { - case goku_plugin.JSON: + case JSON: { e := json.Unmarshal(b.rawBody, &b.object) if e != nil { return e } } - case goku_plugin.AppLicationXML, goku_plugin.TextXML: + case AppLicationXML, TextXML: { e := xml.Unmarshal(b.rawBody, &b.object) if e != nil { @@ -72,7 +133,7 @@ func (b *BodyRequestHandler) Parse() error { } - case goku_plugin.MultipartForm: + case MultipartForm: { r, err := multipartReader(b.contentType, false, b.rawBody) if err != nil { @@ -90,7 +151,7 @@ func (b *BodyRequestHandler) Parse() error { b.form[k] = append(b.form[k], v...) } - b.files = make(map[string]*goku_plugin.FileHeader) + b.files = make(map[string]*http_service.FileHeader) for k, fs := range form.File { if len(fs) > 0 { @@ -103,7 +164,7 @@ func (b *BodyRequestHandler) Parse() error { return err } - b.files[k] = &goku_plugin.FileHeader{ + b.files[k] = &http_service.FileHeader{ FileName: fs[0].Filename, Data: fileData, Header: fs[0].Header, @@ -113,7 +174,7 @@ func (b *BodyRequestHandler) Parse() error { b.object = b.form } - case goku_plugin.FormData: + case FormData: { form, err := url.ParseQuery(string(b.rawBody)) if err != nil { @@ -135,50 +196,15 @@ func (b *BodyRequestHandler) Parse() error { return nil } -//GetForm 获取表单参数 -func (b *BodyRequestHandler) GetForm(key string) string { - - contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { - return "" - } - b.Parse() - - if !b.isInit || b.form == nil { - return "" - } - return b.form.Get(key) -} - -//GetFile 获取文件参数 -func (b *BodyRequestHandler) GetFile(key string) (file *goku_plugin.FileHeader, has bool) { - - contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { - return nil, false - } - - err := b.Parse() - if err != nil { - return nil, false - } - - if !b.isInit || b.files == nil { - return nil, false - } - f, has := b.files[key] - return f, has -} - //SetToForm 设置表单参数 func (b *BodyRequestHandler) SetToForm(key, value string) error { contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { + if contentType != FormData && contentType != MultipartForm { return errorNotForm } - err := b.Parse() + err := b.parse() if err != nil { return err } @@ -196,10 +222,10 @@ func (b *BodyRequestHandler) SetToForm(key, value string) error { //AddForm 新增表单参数 func (b *BodyRequestHandler) AddForm(key, value string) error { contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { + if contentType != FormData && contentType != MultipartForm { return errorNotForm } - err := b.Parse() + err := b.parse() if err != nil { return err } @@ -213,13 +239,13 @@ func (b *BodyRequestHandler) AddForm(key, value string) error { } //AddFile 新增文件参数 -func (b *BodyRequestHandler) AddFile(key string, file *goku_plugin.FileHeader) error { +func (b *BodyRequestHandler) AddFile(key string, file *http_service.FileHeader) error { contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { + if contentType != FormData && contentType != MultipartForm { return errorNotMultipart } - err := b.Parse() + err := b.parse() if err != nil { return err } @@ -229,7 +255,7 @@ func (b *BodyRequestHandler) AddFile(key string, file *goku_plugin.FileHeader) e return nil } if b.files == nil { - b.files = make(map[string]*goku_plugin.FileHeader) + b.files = make(map[string]*http_service.FileHeader) } b.files[key] = file @@ -238,29 +264,14 @@ func (b *BodyRequestHandler) AddFile(key string, file *goku_plugin.FileHeader) e //Clone 克隆body func (b *BodyRequestHandler) Clone() *BodyRequestHandler { - rawbody, _ := b.RawBody() - return newBodyRequestHandler(b.contentType, rawbody) + rawBody, _ := b.RawBody() + return newBodyRequestHandler(b.contentType, rawBody) } -//ContentType 获取contentType -func (b *BodyRequestHandler) ContentType() string { - return b.contentType -} - -//BodyForm 获取表单参数 -func (b *BodyRequestHandler) BodyForm() (url.Values, error) { - - err := b.Parse() - if err != nil { - return nil, err - } - return b.form, nil -} - //BodyInterface 获取请求体对象 func (b *BodyRequestHandler) BodyInterface() (interface{}, error) { - err := b.Parse() + err := b.parse() if err != nil { return nil, err } @@ -268,25 +279,14 @@ func (b *BodyRequestHandler) BodyInterface() (interface{}, error) { return b.object, nil } -//RawBody 获取raw数据 -func (b *BodyRequestHandler) RawBody() ([]byte, error) { - - err := b.Encode() - if err != nil { - return nil, err - } - return b.rawBody, nil - -} - -//Encode encode -func (b *BodyRequestHandler) Encode() error { +//encode encode +func (b *BodyRequestHandler) encode() error { if b.isWriteRaw { return nil } contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { + if contentType != FormData && contentType != MultipartForm { b.isWriteRaw = true return nil } @@ -336,10 +336,10 @@ func (b *BodyRequestHandler) Encode() error { func (b *BodyRequestHandler) SetForm(values url.Values) error { contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { + if contentType != FormData && contentType != MultipartForm { return errorNotForm } - b.Parse() + b.parse() b.form = values b.isWriteRaw = false @@ -347,13 +347,13 @@ func (b *BodyRequestHandler) SetForm(values url.Values) error { } //SetFile 设置文件参数 -func (b *BodyRequestHandler) SetFile(files map[string]*goku_plugin.FileHeader) error { +func (b *BodyRequestHandler) SetFile(files map[string]*http_service.FileHeader) error { contentType, _, _ := mime.ParseMediaType(b.contentType) - if contentType != goku_plugin.FormData && contentType != goku_plugin.MultipartForm { + if contentType != FormData && contentType != MultipartForm { return errorNotForm } - b.Parse() + b.parse() b.files = files // b.form = values b.isWriteRaw = false diff --git a/node/http-context/context.go b/node/http-context/context.go index 091ee096..c677cee0 100644 --- a/node/http-context/context.go +++ b/node/http-context/context.go @@ -3,206 +3,105 @@ package http_context import ( "context" "encoding/json" - "net/http" "github.com/valyala/fasthttp" http_service "github.com/eolinker/eosc/http-service" - access_field "github.com/eolinker/goku/node/common/access-field" uuid "github.com/satori/go.uuid" ) -//Context context +var _ http_service.IHttpContext = (*Context)(nil) + +//Context requestCtx type Context struct { - context *fasthttp.RequestCtx - requestOrg *fasthttp.Request - proxyRequest *fasthttp.Request + requestCtx *fasthttp.RequestCtx + requestOrg *fasthttp.Request + + proxyRequest *ProxyRequest + proxyResponse *fasthttp.Response - Body []byte + body []byte requestID string RestfulParam map[string]string - LogFields *access_field.Fields - request IRequest - labels map[string]string - bodyHandler *BodyRequestHandler -} - -func (ctx *Context) SetStatus(code int, status string) { - panic("implement me") -} - -func (ctx *Context) Request() http_service.RequestReader { - panic("implement me") -} - -func (ctx *Context) ProxyResponse() http_service.ResponseReader { - panic("implement me") + code int + status string + response *Response + requestReader *RequestReader + ctx context.Context } func (ctx *Context) Context() context.Context { - panic("implement me") + if ctx.ctx == nil { + ctx.ctx = context.Background() + } + return ctx.ctx } func (ctx *Context) Value(key interface{}) interface{} { - panic("implement me") + return ctx.Context().Value(key) } func (ctx *Context) WithValue(key, val interface{}) { - panic("implement me") + ctx.ctx = context.WithValue(ctx.Context(), key, val) } -func (ctx *Context) GetHeader(name string) string { - panic("implement me") +func (ctx *Context) Response() http_service.IResponse { + if ctx.response == nil { + ctx.response = NewResponse(ctx.proxyResponse) + } + return ctx.response } -func (ctx *Context) Headers() http.Header { - panic("implement me") +func (ctx *Context) Proxy() http_service.IRequest { + return ctx.proxyRequest } -func (ctx *Context) SetHeader(key, value string) { - panic("implement me") +func (ctx *Context) SetStatus(code int, status string) { + ctx.code, ctx.status = code, status } -func (ctx *Context) AddHeader(key, value string) { - panic("implement me") -} - -func (ctx *Context) DelHeader(key string) { - panic("implement me") -} - -func (ctx *Context) Set() http_service.Header { - panic("implement me") -} - -func (ctx *Context) Append() http_service.Header { - panic("implement me") -} - -func (ctx *Context) Cookie(name string) (*http.Cookie, error) { - panic("implement me") -} - -func (ctx *Context) Cookies() []*http.Cookie { - panic("implement me") -} - -func (ctx *Context) AddCookie(c *http.Cookie) { - panic("implement me") -} - -func (ctx *Context) StatusCode() int { - panic("implement me") -} - -func (ctx *Context) Status() string { - panic("implement me") -} - -func (ctx *Context) GetBody() []byte { - panic("implement me") -} - -func (ctx *Context) Proxy() http_service.Request { - panic("implement me") -} - -func (ctx *Context) SetStoreValue(key string, value interface{}) error { - panic("implement me") -} - -func (ctx *Context) GetStoreValue(key string) (interface{}, bool) { - panic("implement me") +func (ctx *Context) Request() http_service.IRequestReader { + if ctx.requestReader == nil { + ctx.requestReader = NewRequestReader(ctx.requestOrg, ctx.requestCtx.RemoteAddr().String()) + } + return ctx.requestReader } //NewContext 创建Context -func NewContext(ctx *fasthttp.RequestCtx) http_service.IHttpContext { +func NewContext(ctx *fasthttp.RequestCtx) *Context { id := uuid.NewV4() requestID := id.String() newRequest := &ctx.Request newCtx := &Context{ - context: ctx, - requestOrg: fasthttp.AcquireRequest(), - proxyRequest: fasthttp.AcquireRequest(), - requestID: requestID, - LogFields: access_field.NewFields(), + requestCtx: ctx, + requestOrg: fasthttp.AcquireRequest(), + requestID: requestID, } + proxyRequest := fasthttp.AcquireRequest() newRequest.CopyTo(newCtx.requestOrg) - newRequest.CopyTo(newCtx.proxyRequest) + newRequest.CopyTo(proxyRequest) - newCtx.LogFields.RequestHeader = newCtx.requestOrg.Header.String() - newCtx.LogFields.RequestMsg = string(newCtx.Body) - newCtx.LogFields.RequestMsgSize = len(newCtx.Body) - newCtx.LogFields.RequestUri = string(newCtx.requestOrg.RequestURI()) - newCtx.LogFields.RequestID = requestID + newCtx.proxyRequest = NewProxyRequest(NewRequestReader(proxyRequest, "")) return newCtx } -func (ctx *Context) Labels() map[string]string { - if ctx.labels == nil { - ctx.labels = map[string]string{} - } - return ctx.labels -} - -func (ctx *Context) SetLabels(labels map[string]string) { - if ctx.labels == nil { - ctx.labels = make(map[string]string) - } - if labels != nil { - for k, v := range labels { - ctx.labels[k] = v - } - } -} - //RequestId 请求ID func (ctx *Context) RequestId() string { return ctx.requestID } -//func (ctx *Context) Request() IRequest { -// if ctx.request == nil { -// ctx.request = newRequest(ctx.requestOrg) -// } -// return ctx.request -//} - -func (ctx *Context) RequestOrg() *fasthttp.Request { - return ctx.requestOrg -} - -func (ctx *Context) ProxyRequest() *fasthttp.Request { - return ctx.proxyRequest -} - -//func (ctx *Context) ProxyResponse() *fasthttp.Response { -// return ctx.proxyResponse -//} - -func (ctx *Context) BodyHandler() *BodyRequestHandler { - if ctx.bodyHandler == nil { - r := ctx.Request() - body, _ := r.RawBody() - ctx.bodyHandler = newBodyRequestHandler(r.ContentType(), body) - } - return ctx.bodyHandler -} - func (ctx *Context) SetBody(body []byte) { - ctx.context.SetBody(body) + ctx.requestCtx.SetBody(body) } func (ctx *Context) SetResponse(response *fasthttp.Response) { - ctx.Body = response.Body() + ctx.body = response.Body() ctx.proxyResponse = response } //Finish finish func (ctx *Context) Finish() { - ctx.LogFields.ResponseMsg = string(ctx.Body) - ctx.LogFields.ResponseMsgSize = len(ctx.Body) - ctx.proxyResponse.CopyTo(&ctx.context.Response) + ctx.proxyResponse.CopyTo(&ctx.requestCtx.Response) return } @@ -212,10 +111,10 @@ func (ctx *Context) SetError(err error) { "msg": err.Error(), } errByte, _ := json.Marshal(result) - ctx.Body = errByte + ctx.body = errByte } func NotFound(ctx *Context) { - ctx.context.SetStatusCode(404) - ctx.context.SetBody([]byte("404 Not Found")) + ctx.requestCtx.SetStatusCode(404) + ctx.requestCtx.SetBody([]byte("404 Not Found")) } diff --git a/node/http-context/proxy.go b/node/http-context/proxy.go new file mode 100644 index 00000000..3c3a1527 --- /dev/null +++ b/node/http-context/proxy.go @@ -0,0 +1,115 @@ +package http_context + +import ( + "net/http" + "net/url" + + http_service "github.com/eolinker/eosc/http-service" +) + +var _ http_service.IRequest = (*ProxyRequest)(nil) + +type ProxyRequest struct { + *RequestReader + headers http.Header + form url.Values + file map[string]*http_service.FileHeader + contentType string + body []byte + uri *url.URL + method string +} + +func NewProxyRequest(requestReader *RequestReader) *ProxyRequest { + return &ProxyRequest{RequestReader: requestReader} +} + +func (r *ProxyRequest) SetHeader(key, value string) { + if r.headers == nil { + r.headers = r.Headers() + } + r.headers.Set(key, value) +} + +func (r *ProxyRequest) AddHeader(key, value string) { + if r.headers == nil { + r.headers = r.Headers() + } + r.headers.Add(key, value) +} + +func (r *ProxyRequest) DelHeader(key string) { + if r.headers == nil { + r.headers = r.Headers() + } + r.headers.Del(key) +} + +func (r *ProxyRequest) SetForm(values url.Values) error { + r.form = values + return nil +} + +func (r *ProxyRequest) SetToForm(key, value string) error { + if r.form == nil { + form, err := r.BodyForm() + if err != nil { + return err + } + r.form = form + } + r.form.Set(key, value) + return nil +} + +func (r *ProxyRequest) AddForm(key, value string) error { + if r.form == nil { + form, err := r.BodyForm() + if err != nil { + return err + } + r.form = form + } + r.form.Set(key, value) + return nil +} + +func (r *ProxyRequest) AddFile(key string, file *http_service.FileHeader) error { + if r.form == nil { + file, err := r.Files() + if err != nil { + return err + } + r.file = file + } + r.file[key] = file + return nil +} + +func (r *ProxyRequest) SetRaw(contentType string, body []byte) { + r.contentType, r.body = contentType, body +} + +func (r *ProxyRequest) TargetServer() string { + if r.uri == nil { + uri := r.URL() + r.uri = &uri + } + return r.uri.Host +} + +func (r *ProxyRequest) TargetURL() string { + if r.uri == nil { + uri := r.URL() + r.uri = &uri + } + return r.uri.Path +} + +func (r *ProxyRequest) SetMethod(s string) { + r.method = s +} + +func (r *ProxyRequest) SetURL(url url.URL) { + r.uri = &url +} diff --git a/node/http-context/request-reader-old.go b/node/http-context/request-reader-old.go new file mode 100644 index 00000000..ad60205c --- /dev/null +++ b/node/http-context/request-reader-old.go @@ -0,0 +1,122 @@ +package http_context + +//type Value map[string]string +// +//func (h Value) Get(key string) (string, bool) { +// v, ok := h[key] +// return v, ok +//} +// +//type IRequest interface { +// Host() string +// Method() string +// Path() string +// ContentType() string +// Header() Value +// Query() Value +// RawQuery() string +// RawBody() []byte +//} +// +//type ProxyRequest struct { +// req *fasthttp.ProxyRequest +// path string +// host string +// method string +// header Value +// query Value +// rawQuery string +// rawBody []byte +// contentType string +//} +// +//func (r *ProxyRequest) Host() string { +// if r.host == "" { +// r.host = strings.Split(string(r.req.Header.Host()), ":")[0] +// } +// return r.host +//} +// +//func (r *ProxyRequest) Method() string { +// if r.method == "" { +// r.method = string(r.req.Header.Method()) +// } +// return r.method +//} +// +//func (r *ProxyRequest) Path() string { +// if r.path == "" { +// r.path = string(r.req.URI().Path()) +// } +// return r.path +//} +// +//func (r *ProxyRequest) Header() Value { +// if r.header == nil { +// r.header = make(Value) +// hs := strings.Split(r.req.Header.String(), "\r\n") +// for _, h := range hs { +// vs := strings.Split(h, ":") +// if len(vs) < 2 { +// if vs[0] == "" { +// continue +// } +// r.header[vs[0]] = "" +// continue +// } +// r.header[vs[0]] = strings.TrimSpace(vs[1]) +// +// } +// } +// return r.header +//} +// +//func (r *ProxyRequest) Query() Value { +// if r.rawQuery == "" { +// r.rawQuery = string(r.req.URI().QueryString()) +// } +// if r.query == nil { +// r.query = make(Value) +// qs := strings.Split(r.rawQuery, "&") +// for _, q := range qs { +// vs := strings.Split(q, "=") +// if len(vs) < 2 { +// if vs[0] == "" { +// continue +// } +// r.query[vs[0]] = "" +// continue +// } +// r.query[vs[0]] = strings.TrimSpace(vs[1]) +// } +// } +// return r.query +//} +// +//func (r *ProxyRequest) RawQuery() string { +// if r.rawQuery == "" { +// r.rawQuery = string(r.req.URI().QueryString()) +// } +// return r.rawQuery +//} +// +//func (r *ProxyRequest) RawBody() []byte { +// if r.rawBody == nil { +// r.rawBody = r.req.Body() +// } +// return r.rawBody +//} +// +//func (r *ProxyRequest) ContentType() string { +// if r.contentType == "" { +// r.contentType = string(r.req.Header.ContentType()) +// } +// return r.contentType +//} +// +//func newRequest(req *fasthttp.ProxyRequest) IRequest { +// newReq := &ProxyRequest{ +// req: req, +// } +// return newReq +//} diff --git a/node/http-context/request-reader.go b/node/http-context/request-reader.go index 1f1e7a79..3b82a771 100644 --- a/node/http-context/request-reader.go +++ b/node/http-context/request-reader.go @@ -1,65 +1,84 @@ package http_context import ( + "net/http" + "net/url" "strings" + http_service "github.com/eolinker/eosc/http-service" + "github.com/valyala/fasthttp" ) -type Value map[string]string +var _ http_service.IRequestReader = (*RequestReader)(nil) -func (h Value) Get(key string) (string, bool) { - v, ok := h[key] - return v, ok -} - -type IRequest interface { - Host() string - Method() string - Path() string - ContentType() string - Header() Value - Query() Value - RawQuery() string - RawBody() []byte -} - -type Request struct { +type RequestReader struct { req *fasthttp.Request - path string + bodyHandler *BodyRequestHandler + remoteAddr string + clientIP string host string method string - header Value - query Value - rawQuery string rawBody []byte + headers http.Header + scheme string + uri *url.URL contentType string } -func (r *Request) Host() string { - if r.host == "" { - r.host = strings.Split(string(r.req.Header.Host()), ":")[0] - } - return r.host +func NewRequestReader(req *fasthttp.Request, remoteAddr string) *RequestReader { + return &RequestReader{req: req, remoteAddr: remoteAddr} } -func (r *Request) Method() string { - if r.method == "" { - r.method = string(r.req.Header.Method()) +func (r *RequestReader) ContentType() string { + if r.contentType == "" { + r.contentType = string(r.req.Header.ContentType()) } - return r.method + return r.contentType } -func (r *Request) Path() string { - if r.path == "" { - r.path = string(r.req.URI().Path()) +func (r *RequestReader) BodyForm() (url.Values, error) { + if r.bodyHandler == nil { + r.bodyHandler = newBodyRequestHandler(r.ContentType(), r.req.Body()) } - return r.path + return r.bodyHandler.BodyForm() } -func (r *Request) Header() Value { - if r.header == nil { - r.header = make(Value) +func (r *RequestReader) Files() (map[string]*http_service.FileHeader, error) { + if r.bodyHandler == nil { + r.bodyHandler = newBodyRequestHandler(r.ContentType(), r.req.Body()) + } + return r.bodyHandler.Files() +} + +func (r *RequestReader) GetForm(key string) string { + if r.bodyHandler == nil { + r.bodyHandler = newBodyRequestHandler(r.ContentType(), r.req.Body()) + } + return r.bodyHandler.GetForm(key) +} + +func (r *RequestReader) GetFile(key string) (file *http_service.FileHeader, has bool) { + if r.bodyHandler == nil { + r.bodyHandler = newBodyRequestHandler(r.ContentType(), r.req.Body()) + } + return r.bodyHandler.GetFile(key) +} + +func (r *RequestReader) RawBody() ([]byte, error) { + if r.bodyHandler == nil { + r.bodyHandler = newBodyRequestHandler(r.ContentType(), r.req.Body()) + } + return r.bodyHandler.RawBody() +} + +func (r *RequestReader) GetHeader(name string) string { + return r.Headers().Get(name) +} + +func (r *RequestReader) Headers() http.Header { + if r.headers == nil { + r.headers = make(http.Header) hs := strings.Split(r.req.Header.String(), "\r\n") for _, h := range hs { vs := strings.Split(h, ":") @@ -67,62 +86,66 @@ func (r *Request) Header() Value { if vs[0] == "" { continue } - r.header[vs[0]] = "" + r.headers[vs[0]] = []string{""} continue } - r.header[vs[0]] = strings.TrimSpace(vs[1]) + r.headers[vs[0]] = []string{strings.TrimSpace(vs[1])} } } - return r.header + return r.headers } -func (r *Request) Query() Value { - if r.rawQuery == "" { - r.rawQuery = string(r.req.URI().QueryString()) +func (r *RequestReader) Method() string { + if r.method == "" { + r.method = string(r.req.Header.Method()) } - if r.query == nil { - r.query = make(Value) - qs := strings.Split(r.rawQuery, "&") - for _, q := range qs { - vs := strings.Split(q, "=") - if len(vs) < 2 { - if vs[0] == "" { - continue - } - r.query[vs[0]] = "" - continue - } - r.query[vs[0]] = strings.TrimSpace(vs[1]) + return r.method +} + +func (r *RequestReader) URL() url.URL { + if r.uri == nil { + r.uri, _ = url.Parse(r.req.URI().String()) + } + return *r.uri +} + +func (r *RequestReader) RequestURI() string { + return string(r.req.RequestURI()) +} + +func (r *RequestReader) Host() string { + if r.host == "" { + r.host = strings.Split(string(r.req.Header.Host()), ":")[0] + } + return r.host +} + +func (r *RequestReader) RemoteAddr() string { + if r.clientIP == "" { + clientIP := string(r.req.Header.Peek("X-Forwarded-For")) + if index := strings.IndexByte(clientIP, ','); index >= 0 { + clientIP = clientIP[0:index] } + clientIP = strings.TrimSpace(clientIP) + if len(clientIP) < 1 { + clientIP = strings.TrimSpace(string(r.req.Header.Peek("X-Real-Ip"))) + if len(clientIP) < 1 { + clientIP = r.remoteAddr + } + } + r.clientIP = clientIP } - return r.query + return r.clientIP } -func (r *Request) RawQuery() string { - if r.rawQuery == "" { - r.rawQuery = string(r.req.URI().QueryString()) +func (r *RequestReader) Scheme() string { + if r.scheme == "" { + r.scheme = string(r.req.URI().Scheme()) } - return r.rawQuery + return r.scheme } -func (r *Request) RawBody() []byte { - if r.rawBody == nil { - r.rawBody = r.req.Body() - } - return r.rawBody -} - -func (r *Request) ContentType() string { - if r.contentType == "" { - r.contentType = string(r.req.Header.ContentType()) - } - return r.contentType -} - -func newRequest(req *fasthttp.Request) IRequest { - newReq := &Request{ - req: req, - } - return newReq +func (r *RequestReader) Request() *fasthttp.Request { + return r.req } diff --git a/node/http-context/response.go b/node/http-context/response.go new file mode 100644 index 00000000..6dd40731 --- /dev/null +++ b/node/http-context/response.go @@ -0,0 +1,110 @@ +package http_context + +import ( + "net/http" + "strconv" + "strings" + + http_service "github.com/eolinker/eosc/http-service" + + "github.com/valyala/fasthttp" +) + +var _ http_service.IResponse = (*Response)(nil) + +type Response struct { + response *fasthttp.Response + headers http.Header + code int + status string +} + +func (r *Response) Headers() http.Header { + if r.headers == nil { + r.headers = make(http.Header) + hs := strings.Split(r.response.Header.String(), "\r\n") + for _, h := range hs { + vs := strings.Split(h, ":") + if len(vs) < 2 { + if vs[0] == "" { + continue + } + r.headers[vs[0]] = []string{""} + continue + } + r.headers[vs[0]] = []string{strings.TrimSpace(vs[1])} + } + } + return r.headers +} + +func NewResponse(response *fasthttp.Response) *Response { + return &Response{response: response} +} + +func (r *Response) initHeader() { + r.headers = make(http.Header) + hs := strings.Split(r.response.Header.String(), "\r\n") + for _, h := range hs { + vs := strings.Split(h, ":") + if len(vs) < 2 { + if vs[0] == "" { + continue + } + r.headers[vs[0]] = []string{""} + continue + } + r.headers[vs[0]] = []string{strings.TrimSpace(vs[1])} + } +} + +func (r *Response) GetHeader(name string) string { + if r.headers == nil { + r.initHeader() + } + return r.headers.Get(name) +} + +func (r *Response) GetBody() []byte { + return r.response.Body() +} + +func (r *Response) StatusCode() int { + return r.response.StatusCode() +} + +func (r *Response) Status() string { + return strconv.Itoa(r.response.StatusCode()) +} + +func (r *Response) SetHeader(key, value string) { + if r.headers == nil { + r.response.Header.Set(key, value) + return + } + r.headers.Set(key, value) +} + +func (r *Response) AddHeader(key, value string) { + if r.headers == nil { + r.response.Header.Add(key, value) + return + } + r.headers.Add(key, value) +} + +func (r *Response) DelHeader(key string) { + if r.headers == nil { + r.response.Header.Del(key) + return + } + r.headers.Del(key) +} + +func (r *Response) SetStatus(code int, status string) { + r.code, r.status = code, status +} + +func (r *Response) SetBody(bytes []byte) { + r.response.SetBody(bytes) +} diff --git a/node/http-context/status.go b/node/http-context/status.go deleted file mode 100644 index 118e5437..00000000 --- a/node/http-context/status.go +++ /dev/null @@ -1,14 +0,0 @@ -package http_context - -//type IStatus interface { -// SetStatus(statusCode int) -// GetStatus() int -//} -// -//func (ctx *Context) SetStatus(statusCode int) { -// ctx.context.SetStatusCode(statusCode) -//} -// -//func (ctx *Context) GetStatus() int { -// return ctx.context.Response.StatusCode() -//} diff --git a/router/router-http/config.go b/router/router-http/config.go index f345ebc4..ddc76283 100644 --- a/router/router-http/config.go +++ b/router/router-http/config.go @@ -42,7 +42,7 @@ type Config struct { Rules []Rule } -//toPath 根据路由指标Location、Header、Query生成相应Checker并封装成RulePath切片返回 +//toPath 根据路由指标Location、IHeader、Query生成相应Checker并封装成RulePath切片返回 func (r *Rule) toPath() ([]router.RulePath, error) { path := make([]router.RulePath, 0, len(r.Header)+len(r.Query)+1) diff --git a/service/service.go b/service/service.go index 9e4c93c2..049437a4 100644 --- a/service/service.go +++ b/service/service.go @@ -4,8 +4,6 @@ import ( "time" http_service "github.com/eolinker/eosc/http-service" - - http_context "github.com/eolinker/goku/node/http-context" ) //CheckSkill 检查目标技能是否符合 @@ -15,10 +13,10 @@ func CheckSkill(skill string) bool { //IService github.com/eolinker/goku/service.service.IService type IService interface { - Handle(ctx *http_context.Context, router IRouterEndpoint) error + Handle(ctx http_service.IHttpContext) error } -//IRouterEndpoint 实现了返回路由规则信息方法的接口,如返回location、Host、Header、Query +//IRouterEndpoint 实现了返回路由规则信息方法的接口,如返回location、Host、IHeader、Query type IRouterEndpoint interface { Location() (http_service.Checker, bool) Header(name string) (http_service.Checker, bool)