pkg/context/http/context.go (154 lines of code) (raw):

/* * 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. */ package http import ( "context" "encoding/json" "math" "net" "net/http" "net/url" "strings" "time" ) import ( "github.com/dubbo-go-pixiu/pixiu-api/pkg/router" ) import ( "github.com/apache/dubbo-go-pixiu/pkg/client" "github.com/apache/dubbo-go-pixiu/pkg/common/constant" "github.com/apache/dubbo-go-pixiu/pkg/logger" "github.com/apache/dubbo-go-pixiu/pkg/model" ) const abortIndex int8 = math.MaxInt8 / 2 // HttpContext http context type HttpContext struct { //Deprecated: waiting to delete Index int8 //Deprecated: waiting to delete Filters FilterChain Timeout time.Duration Ctx context.Context Params map[string]any // localReply Means that the request was interrupted, // which may occur in the Decode or Encode stage localReply bool // statusCode code will be return statusCode int // localReplyBody: happen error localReplyBody []byte // the response context will return. TargetResp client.Response // client call response. SourceResp any HttpConnectionManager model.HttpConnectionManagerConfig Route *model.RouteAction Api *router.API Request *http.Request Writer http.ResponseWriter } type ( // ErrResponse err response. ErrResponse struct { Message string `json:"message"` } // FilterFunc filter func, filter FilterFunc func(c *HttpContext) // FilterChain filter chain FilterChain []FilterFunc ) // Deprecated: Next logic for lookup filter func (hc *HttpContext) Next() { } // Reset reset http context func (hc *HttpContext) Reset() { hc.Ctx = nil hc.Index = -1 hc.Filters = []FilterFunc{} hc.Route = nil hc.Api = nil hc.TargetResp = nil hc.SourceResp = nil hc.statusCode = 0 hc.localReply = false hc.localReplyBody = nil } // RouteEntry set route func (hc *HttpContext) RouteEntry(r *model.RouteAction) { hc.Route = r } // GetRouteEntry get route func (hc *HttpContext) GetRouteEntry() *model.RouteAction { return hc.Route } // AddHeader add header func (hc *HttpContext) AddHeader(k, v string) { hc.Writer.Header().Add(k, v) } // GetHeader get header func (hc *HttpContext) GetHeader(k string) string { return hc.Request.Header.Get(k) } // AllHeaders get all headers func (hc *HttpContext) AllHeaders() http.Header { return hc.Request.Header } // GetUrl get http request url func (hc *HttpContext) GetUrl() string { return hc.Request.URL.Path } func (hc *HttpContext) SetUrl(url string) { hc.Request.URL.Path = url } // GetMethod get method, POST/GET ... func (hc *HttpContext) GetMethod() string { return hc.Request.Method } // GetClientIP get client IP func (hc *HttpContext) GetClientIP() string { xForwardedFor := hc.Request.Header.Get("X-Forwarded-For") ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0]) if len(ip) != 0 { return ip } ip = strings.TrimSpace(hc.Request.Header.Get("X-Real-Ip")) if len(ip) != 0 { return ip } if ip, _, err := net.SplitHostPort(strings.TrimSpace(hc.Request.RemoteAddr)); err == nil && len(ip) != 0 { return ip } return "" } // GetApplicationName get application name func (hc *HttpContext) GetApplicationName() string { if u, err := url.Parse(hc.Request.RequestURI); err == nil { return strings.Split(u.Path, "/")[0] } return "" } // SendLocalReply Means that the request was interrupted and UnaryResponse will be sent directly // Even if it’s currently in to Decode stage func (hc *HttpContext) SendLocalReply(status int, body []byte) { hc.localReply = true hc.statusCode = status hc.localReplyBody = body hc.TargetResp = &client.UnaryResponse{Data: body} if json.Valid(body) { hc.AddHeader(constant.HeaderKeyContextType, constant.HeaderValueApplicationJson) } else { hc.AddHeader(constant.HeaderKeyContextType, constant.HeaderValueTextPlain) } writer := hc.Writer writer.WriteHeader(status) _, err := writer.Write(body) if err != nil { logger.Errorf("write fail: %v", err) } } func (hc *HttpContext) GetLocalReplyBody() []byte { return hc.localReplyBody } func (hc *HttpContext) GetStatusCode() int { return hc.statusCode } func (hc *HttpContext) StatusCode(code int) { hc.statusCode = code } func (hc *HttpContext) LocalReply() bool { return hc.localReply } // API sets the API to http context func (hc *HttpContext) API(api router.API) { if hc.Timeout > api.Timeout { hc.Timeout = api.Timeout } hc.Api = &api } // GetAPI get api func (hc *HttpContext) GetAPI() *router.API { return hc.Api } // Deprecated: Abort filter chain break , filter after the current filter will not executed. func (hc *HttpContext) Abort() { hc.Index = abortIndex } // Deprecated: AppendFilterFunc append filter func. func (hc *HttpContext) AppendFilterFunc(ff ...FilterFunc) { for _, v := range ff { hc.Filters = append(hc.Filters, v) } } func (hc *HttpContext) GenerateHash() string { req := hc.Request return req.Method + "." + req.RequestURI }