package proxy import ( "bytes" "strings" "golang.org/x/net/html" ) // rewriteHTMLBody parses HTML and rewrites absolute URLs in known attributes // so they include the token prefix. This is needed because many sites (e.g. // GitHub) use Content-Security-Policy that blocks inline scripts, making the // JS-injection approach unreliable. func rewriteHTMLBody(body []byte, prefix string, host string, proto string) []byte { if prefix == "" { return body } doc, err := html.Parse(bytes.NewReader(body)) if err != nil { return body } rewriteNode(doc, prefix, host, proto) var buf bytes.Buffer if err := html.Render(&buf, doc); err != nil { return body } return buf.Bytes() } // urlAttrs lists element attributes that contain URLs which should be rewritten. var urlAttrs = []string{ "href", "src", "action", "poster", "formaction", "cite", "longdesc", "profile", "background", "data-url", "data-href", } func rewriteNode(n *html.Node, prefix string, host string, proto string) { if n.Type == html.ElementNode { for i := range n.Attr { attr := &n.Attr[i] if isURLAttr(attr.Key) { attr.Val = rewriteURL(attr.Val, prefix) // 将 href 的相对路径显式写成绝对路径,避免浏览器根据当前 // 页面协议猜测(防止 http 页面中的链接被解析成 https)。 if host != "" && proto != "" && strings.EqualFold(attr.Key, "href") && strings.HasPrefix(attr.Val, "/") && !strings.HasPrefix(attr.Val, "//") { attr.Val = proto + "://" + host + attr.Val } continue } // if strings.EqualFold(n.Data, "meta") && strings.EqualFold(attr.Key, "content") && isRefreshMeta(n) { attr.Val = rewriteRefreshContent(attr.Val, prefix) } } // Rewrite url(...) inside