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  }