diff --git a/internal/nodes/http_request.go b/internal/nodes/http_request.go index aca068c..bd014cd 100644 --- a/internal/nodes/http_request.go +++ b/internal/nodes/http_request.go @@ -60,7 +60,7 @@ type HTTPRequest struct { // 初始化 func (this *HTTPRequest) init() { - this.writer = NewHTTPWriter(this.RawWriter) + this.writer = NewHTTPWriter(this, this.RawWriter) this.web = &serverconfigs.HTTPWebConfig{} this.uri = this.RawReq.URL.RequestURI() this.rawURI = this.uri @@ -101,10 +101,18 @@ func (this *HTTPRequest) Do() { } // Gzip - // TODO 需要实现 + shouldCloseWriter := false + if this.web.Gzip != nil && this.web.Gzip.IsOn && this.web.Gzip.Level > 0 { + shouldCloseWriter = true + this.writer.Gzip(this.web.Gzip) + } // 开始调用 this.doBegin() + + if shouldCloseWriter { + this.writer.Close() + } } // 开始调用 @@ -225,6 +233,11 @@ func (this *HTTPRequest) configureWeb(web *serverconfigs.HTTPWebConfig, isTop bo this.web.Websocket = web.Websocket } + // gzip + if web.GzipRef != nil && (web.GzipRef.IsPrior || isTop) { + this.web.Gzip = web.Gzip + } + // 重写规则 if len(web.RewriteRefs) > 0 { for index, ref := range web.RewriteRefs { @@ -235,7 +248,7 @@ func (this *HTTPRequest) configureWeb(web *serverconfigs.HTTPWebConfig, isTop bo if !rewriteRule.IsOn { continue } - if replace, varMapping, isMatched := rewriteRule.Match(rawPath, this.Format); isMatched { + if replace, varMapping, isMatched := rewriteRule.MatchRequest(rawPath, this.Format); isMatched { this.addVarMapping(varMapping) this.rewriteRule = rewriteRule @@ -267,10 +280,11 @@ func (this *HTTPRequest) configureWeb(web *serverconfigs.HTTPWebConfig, isTop bo } this.uri = replace - // 终止解析的三个条件: + // 终止解析的几个个条件: // isBreak = true // mode = redirect // replace = external url + // replace = uri if rewriteRule.IsBreak || rewriteRule.Mode == serverconfigs.HTTPRewriteModeRedirect { return nil } @@ -363,6 +377,8 @@ func (this *HTTPRequest) Format(source string) string { return this.rawURI case "requestPath": return this.requestPath() + case "requestPathExtension": // TODO 需要添加到文档中 + return filepath.Ext(this.requestPath()) case "requestLength": return strconv.FormatInt(this.requestLength(), 10) case "requestTime": @@ -455,7 +471,26 @@ func (this *HTTPRequest) Format(source string) string { return this.requestHeader(suffix) } - // backend. + // response. + // TODO 需要在文档中添加说明 + if prefix == "response" { + switch suffix { + case "contentType": + return this.writer.Header().Get("Content-Type") + } + + // response.xxx.xxx + dotIndex := strings.Index(suffix, ".") + if dotIndex < 0 { + return "${" + varName + "}" + } + switch suffix[:dotIndex] { + case "header": + return this.writer.Header().Get(suffix[dotIndex+1:]) + } + } + + // origin. if prefix == "origin" { if this.origin != nil { switch suffix { diff --git a/internal/nodes/http_request_root.go b/internal/nodes/http_request_root.go index faa6125..2790ffa 100644 --- a/internal/nodes/http_request_root.go +++ b/internal/nodes/http_request_root.go @@ -151,7 +151,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) { // mime type if this.web.ResponseHeaderPolicy == nil || !this.web.ResponseHeaderPolicy.IsOn || !this.web.ResponseHeaderPolicy.ContainsHeader("CONTENT-TYPE") { - ext := filepath.Ext(requestPath) + ext := filepath.Ext(filePath) if len(ext) > 0 { mimeType := mime.TypeByExtension(ext) if len(mimeType) > 0 { diff --git a/internal/nodes/http_writer.go b/internal/nodes/http_writer.go index ca76b72..4d1b6ed 100644 --- a/internal/nodes/http_writer.go +++ b/internal/nodes/http_writer.go @@ -8,10 +8,12 @@ import ( "github.com/iwind/TeaGo/logs" "net" "net/http" + "strings" ) // 响应Writer type HTTPWriter struct { + req *HTTPRequest writer http.ResponseWriter gzipConfig *serverconfigs.HTTPGzipConfig @@ -27,8 +29,9 @@ type HTTPWriter struct { } // 包装对象 -func NewHTTPWriter(httpResponseWriter http.ResponseWriter) *HTTPWriter { +func NewHTTPWriter(req *HTTPRequest, httpResponseWriter http.ResponseWriter) *HTTPWriter { return &HTTPWriter{ + req: req, writer: httpResponseWriter, } } @@ -60,16 +63,31 @@ func (this *HTTPWriter) Prepare(size int64) { return } - // 尺寸和类型 - if size < this.gzipConfig.MinBytes() { + // 判断Accept是否支持gzip + if !strings.Contains(this.req.requestHeader("Accept-Encoding"), "gzip") { return } - contentType := this.Header().Get("Content-Type") - if !this.gzipConfig.MatchContentType(contentType) { + // 尺寸和类型 + if size < this.gzipConfig.MinBytes() || (this.gzipConfig.MaxBytes() > 0 && size > this.gzipConfig.MaxBytes()) { return } + // 校验其他条件 + if this.gzipConfig.Conds != nil { + if len(this.gzipConfig.Conds.Groups) > 0 { + if !this.gzipConfig.Conds.MatchRequest(this.req.Format) || !this.gzipConfig.Conds.MatchResponse(this.req.Format) { + return + } + } else { + // 默认校验文档类型 + contentType := this.writer.Header().Get("Content-Type") + if len(contentType) > 0 && (!strings.HasPrefix(contentType, "text/") && !strings.HasPrefix(contentType, "application/")) { + return + } + } + } + // 如果已经有编码则不处理 if len(this.writer.Header().Get("Content-Encoding")) > 0 { return