package main import ( "bytes" "fmt" "io" "os" "text/template" "time" ) var errPageRawTmpl = ` COW Proxy

{{.H1}}

{{.Msg}} {{.Form}}
Generated by COW at {{.T}} ` var blockedFormRawTmpl = `

Refresh to retry or add {{.Domain}} to
blocked sites
` var directFormRawTmpl = `
direct accessible sites
` // Do not end with "\r\n" so we can add more header later var headRawTmpl = "HTTP/1.1 {{.CodeReason}}\r\n" + "Connection: keep-alive\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n" + "Content-Type: text/html\r\n" + "Content-Length: {{.Length}}\r\n" var errPageTmpl, headTmpl, blockedFormTmpl, directFormTmpl *template.Template func init() { var err error if headTmpl, err = template.New("errorHead").Parse(headRawTmpl); err != nil { fmt.Println("Internal error on generating error head template") os.Exit(1) } if errPageTmpl, err = template.New("errorPage").Parse(errPageRawTmpl); err != nil { fmt.Println("Internal error on generating error page template") os.Exit(1) } if blockedFormTmpl, err = template.New("blockedForm").Parse(blockedFormRawTmpl); err != nil { fmt.Println("Internal error on generating blocked form template") os.Exit(1) } if directFormTmpl, err = template.New("directForm").Parse(directFormRawTmpl); err != nil { fmt.Println("Internal error on generating direct form template") os.Exit(1) } } func genErrorPage(h1, msg, form string) (string, error) { var err error data := struct { H1 string Msg string Form string T string }{ h1, msg, form, time.Now().Format(time.ANSIC), } buf := new(bytes.Buffer) err = errPageTmpl.Execute(buf, data) return buf.String(), err } func sendPageGeneric(w io.Writer, codeReason, h1, msg, form, addHeader string) { page, err := genErrorPage(h1, msg, form) if err != nil { errl.Println("Error generating error page:", err) return } data := struct { CodeReason string Length int }{ codeReason, len(page), } buf := new(bytes.Buffer) if err := headTmpl.Execute(buf, data); err != nil { errl.Println("Error generating error page header:", err) return } buf.WriteString(addHeader) buf.WriteString("\r\n") buf.WriteString(page) w.Write(buf.Bytes()) } func sendErrorPage(w io.Writer, codeReason, h1, msg string) { sendPageGeneric(w, codeReason, "[Error] "+h1, msg, "", "") } func sendRedirectPage(w io.Writer, location string) { sendPageGeneric(w, "302 Found", "Domain added to blocked list", "Redirect to "+location, "", fmt.Sprintf("Location: %s\r\n", location)) } func sendBlockedErrorPage(c *clientConn, codeReason, h1, msg string, r *Request) { // If host is IP or in always DS, we can't add it to blocked or direct domain list. Just // return ordinary error page. h, _ := splitHostPort(r.URL.HostPort) if hostIsIP(r.URL.HostPort) || domainSet.isHostInAlwaysDs(h) { sendErrorPage(c, codeReason, h1, msg) return } data := struct { ProxyAddr string Host string Domain string }{ c.proxy.addr, h, host2Domain(r.URL.HostPort), } buf := new(bytes.Buffer) if err := blockedFormTmpl.Execute(buf, data); err != nil { errl.Println("Error generating blocked form:", err) return } if !domainSet.isHostDirect(h) { if err := directFormTmpl.Execute(buf, data); err != nil { errl.Println("Error generating direct form:", err) return } } sendPageGeneric(c, codeReason, "[Error] "+h1, msg, buf.String(), "") }