github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/http_request_page.go (about) 1 package nodes 2 3 import ( 4 "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" 5 "github.com/TeaOSLab/EdgeNode/internal/remotelogs" 6 "github.com/TeaOSLab/EdgeNode/internal/utils" 7 "github.com/iwind/TeaGo/Tea" 8 "net/http" 9 "os" 10 "path" 11 "strings" 12 ) 13 14 const defaultPageContentType = "text/html; charset=utf-8" 15 16 // 请求特殊页面 17 func (this *HTTPRequest) doPage(status int) (shouldStop bool) { 18 if len(this.web.Pages) == 0 { 19 // 集群自定义页面 20 if this.nodeConfig != nil && this.ReqServer != nil { 21 var httpPagesPolicy = this.nodeConfig.FindHTTPPagesPolicyWithClusterId(this.ReqServer.ClusterId) 22 if httpPagesPolicy != nil && httpPagesPolicy.IsOn && len(httpPagesPolicy.Pages) > 0 { 23 return this.doPageLookup(httpPagesPolicy.Pages, status) 24 } 25 } 26 27 return false 28 } 29 30 // 查找当前网站自定义页面 31 shouldStop = this.doPageLookup(this.web.Pages, status) 32 if shouldStop { 33 return 34 } 35 36 // 集群自定义页面 37 if this.nodeConfig != nil && this.ReqServer != nil { 38 var httpPagesPolicy = this.nodeConfig.FindHTTPPagesPolicyWithClusterId(this.ReqServer.ClusterId) 39 if httpPagesPolicy != nil && httpPagesPolicy.IsOn && len(httpPagesPolicy.Pages) > 0 { 40 return this.doPageLookup(httpPagesPolicy.Pages, status) 41 } 42 } 43 44 return 45 } 46 47 func (this *HTTPRequest) doPageLookup(pages []*serverconfigs.HTTPPageConfig, status int) (shouldStop bool) { 48 var url = this.URL() 49 for _, page := range pages { 50 if !page.MatchURL(url) { 51 continue 52 } 53 if page.Match(status) { 54 if len(page.BodyType) == 0 || page.BodyType == serverconfigs.HTTPPageBodyTypeURL { 55 if urlSchemeRegexp.MatchString(page.URL) { 56 var newStatus = page.NewStatus 57 if newStatus <= 0 { 58 newStatus = status 59 } 60 this.doURL(http.MethodGet, page.URL, "", newStatus, true) 61 return true 62 } else { 63 var realpath = path.Clean(page.URL) 64 if !strings.HasPrefix(realpath, "/pages/") && !strings.HasPrefix(realpath, "pages/") { // only files under "/pages/" can be used 65 var msg = "404 page not found: '" + page.URL + "'" 66 this.writer.Header().Set("Content-Type", defaultPageContentType) 67 this.writer.WriteHeader(http.StatusNotFound) 68 _, _ = this.writer.Write([]byte(msg)) 69 return true 70 } 71 var file = Tea.Root + Tea.DS + realpath 72 fp, err := os.Open(file) 73 if err != nil { 74 var msg = "404 page not found: '" + page.URL + "'" 75 this.writer.Header().Set("Content-Type", defaultPageContentType) 76 this.writer.WriteHeader(http.StatusNotFound) 77 _, _ = this.writer.Write([]byte(msg)) 78 return true 79 } 80 defer func() { 81 _ = fp.Close() 82 }() 83 84 stat, err := fp.Stat() 85 if err != nil { 86 var msg = "404 could not read page content: '" + page.URL + "'" 87 this.writer.Header().Set("Content-Type", defaultPageContentType) 88 this.writer.WriteHeader(http.StatusNotFound) 89 _, _ = this.writer.Write([]byte(msg)) 90 return true 91 } 92 93 // 修改状态码 94 if page.NewStatus > 0 { 95 // 自定义响应Headers 96 this.writer.Header().Set("Content-Type", defaultPageContentType) 97 this.ProcessResponseHeaders(this.writer.Header(), page.NewStatus) 98 this.writer.Prepare(nil, stat.Size(), page.NewStatus, true) 99 this.writer.WriteHeader(page.NewStatus) 100 } else { 101 this.writer.Header().Set("Content-Type", defaultPageContentType) 102 this.ProcessResponseHeaders(this.writer.Header(), status) 103 this.writer.Prepare(nil, stat.Size(), status, true) 104 this.writer.WriteHeader(status) 105 } 106 var buf = utils.BytePool1k.Get() 107 _, err = utils.CopyWithFilter(this.writer, fp, buf.Bytes, func(p []byte) []byte { 108 return []byte(this.Format(string(p))) 109 }) 110 utils.BytePool1k.Put(buf) 111 if err != nil { 112 if !this.canIgnore(err) { 113 remotelogs.Warn("HTTP_REQUEST_PAGE", "write to client failed: "+err.Error()) 114 } 115 } else { 116 this.writer.SetOk() 117 } 118 } 119 120 return true 121 } else if page.BodyType == serverconfigs.HTTPPageBodyTypeHTML { 122 // 这里需要实现设置Status,因为在Format()中可以获取${status}等变量 123 if page.NewStatus > 0 { 124 this.writer.statusCode = page.NewStatus 125 } else { 126 this.writer.statusCode = status 127 } 128 var content = this.Format(page.Body) 129 130 // 修改状态码 131 if page.NewStatus > 0 { 132 // 自定义响应Headers 133 this.writer.Header().Set("Content-Type", defaultPageContentType) 134 this.ProcessResponseHeaders(this.writer.Header(), page.NewStatus) 135 this.writer.Prepare(nil, int64(len(content)), page.NewStatus, true) 136 this.writer.WriteHeader(page.NewStatus) 137 } else { 138 this.writer.Header().Set("Content-Type", defaultPageContentType) 139 this.ProcessResponseHeaders(this.writer.Header(), status) 140 this.writer.Prepare(nil, int64(len(content)), status, true) 141 this.writer.WriteHeader(status) 142 } 143 144 _, err := this.writer.WriteString(content) 145 if err != nil { 146 if !this.canIgnore(err) { 147 remotelogs.Warn("HTTP_REQUEST_PAGE", "write to client failed: "+err.Error()) 148 } 149 } else { 150 this.writer.SetOk() 151 } 152 return true 153 } else if page.BodyType == serverconfigs.HTTPPageBodyTypeRedirectURL { 154 var newURL = this.Format(page.URL) 155 if len(newURL) == 0 { 156 newURL = "/" 157 } 158 if page.NewStatus > 0 && httpStatusIsRedirect(page.NewStatus) { 159 httpRedirect(this.writer, this.RawReq, newURL, page.NewStatus) 160 } else { 161 httpRedirect(this.writer, this.RawReq, newURL, http.StatusTemporaryRedirect) 162 } 163 this.writer.SetOk() 164 return true 165 } 166 } 167 } 168 return false 169 }