-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathinit.go
121 lines (112 loc) · 5.5 KB
/
init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
)
type configuration struct { // The configuration type holds configuration data
Host string // Host string for the webserver to listen on
Port string // Port string for the webserver to listen on
PublicDir string // Path string to the directory to serve static files from
CacheStatic bool // Boolean to enable or disable file caching
StripCORS bool // Boolean to strip CORS headers
StripIntegrityAttributes bool // Boolean to strip 'integrity' attributes in HTML
StripFrameOptions bool // Boolean to strip X-Frame-Options headers
ModifyHTML bool // Boolean to modify HTML
ModifyCSS bool // Boolean to modify CSS
ExternalURL string // External URL string for formatting proxied HTML
EnableTLS bool // Boolean to serve with TLS
Verbose bool // Boolean to disable logs of 404 errors
TLSCertPath string // Path to SSL Certificate
TLSKeyPath string // Path to private key for certificate
}
type reqHandler func(http.ResponseWriter, *http.Request) *reqError
var config configuration // configuration for the entire program
var notFoundPage []byte // Cached 404 page
func init() {
// Configuration flags
flag.BoolVar(&config.CacheStatic, "cachestatic", true, "cache specific heavily used static files")
flag.BoolVar(&config.StripCORS, "cors", true, "strip Cross Origin Resource Policy headers")
flag.BoolVar(&config.EnableTLS, "tls", false, "enable serving with TLS (https)")
flag.BoolVar(&config.Verbose, "verbose", false, "enable printing 404 errors to STDOUT")
flag.BoolVar(&config.StripFrameOptions, "frameoptions", true, "strip Frame Options headers to allow framing (if disabled this will break pub/index.html)")
flag.BoolVar(&config.StripIntegrityAttributes, "integrity", true, "strip 'integrity' attributes in HTML")
flag.BoolVar(&config.ModifyCSS, "css", true, "modify CSS to pass URLs through the webproxy")
flag.BoolVar(&config.ModifyHTML, "HTML", true, "modify HTML to pass URLs through the webproxy")
flag.StringVar(&config.Host, "host", "localhost", "host to listen on for the webserver")
flag.StringVar(&config.Port, "port", "8000", "port to listen on for the webserver")
flag.StringVar(&config.PublicDir, "pubdir", "pub", "path to the static files the webserver should serve")
flag.StringVar(&config.TLSCertPath, "tls-cert", "", "path to certificate file")
flag.StringVar(&config.TLSKeyPath, "tls-key", "", "path to private key for certificate")
flag.StringVar(&config.ExternalURL, "exturl", "", "external URL for formatting proxied HTML files to link back to the webproxy")
flag.Parse() // Parse the rest of the flags
}
func main() { // Main functions
if config.ExternalURL == "" {
config.ExternalURL = "http://" + config.Host + ":" + config.Port // If nothing is specified, use the default host and port
}
if config.CacheStatic == true { // Cache certain static files if they exist and if config.CacheStatic is set to true
notFoundPage, err = ioutil.ReadFile(config.PublicDir + "/404.html")
if err != nil {
panic(err)
}
}
// Create a HTTP Server, and handle requests and errors
http.Handle("/", http.FileServer(http.Dir(config.PublicDir)))
http.Handle("/p/", reqHandler(proxyHandler))
bind := fmt.Sprintf("%s:%s", config.Host, config.Port)
fmt.Printf("Bypass listening on %s...\n", bind)
if !config.EnableTLS {
err = http.ListenAndServe(bind, nil)
if err != nil {
panic(err)
}
} else if config.EnableTLS {
if config.TLSCertPath == "" {
panic(errors.New("tls-cert flag must not be empty"))
}
if config.TLSKeyPath == "" {
panic(errors.New("tls-key flag must not be empty"))
}
fmt.Println("Serving with TLS...")
err = http.ListenAndServeTLS(bind, config.TLSCertPath, config.TLSKeyPath, nil)
if err != nil {
panic(err)
}
}
}
func (fn reqHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Allows us to pass errors back through our http handling functions
if e := fn(w, r); e != nil { // e is *appError, not os.Error
if e.Code == 404 { // Serve a pretty (potentially cached) file for 404 errors, if it exists
w.WriteHeader(404)
if config.Verbose && e.Error != nil {
fmt.Println(e.Error.Error(), "\n", e.Message) // Print the error message
}
if notFoundPage != nil && config.CacheStatic { // Serve the cached file if one exists
io.WriteString(w, string(notFoundPage))
} else { // Read a non-cached file from disk and serve it because there isn't a cached one
file, err := ioutil.ReadFile(config.PublicDir + "/404.html")
if err != nil {
if e.Error == nil { // Is there an included Error type
http.Error(w, e.Message, e.Code) // Serve a generic error message if the file isn't cached and doesn't exist
} else {
http.Error(w, e.Message+"\n"+e.Error.Error(), e.Code) // Serve a generic error message if the file isn't cached and doesn't exist
}
return
}
io.WriteString(w, string(file))
}
} else { // If it's not a 404 error just serve a generic message
if e.Error == nil {
fmt.Println(e.Message)
http.Error(w, e.Message, e.Code) // Serve a generic error message if the file isn't cached and doesn't exist
} else {
fmt.Println(e.Error.Error(), "\n", e.Message) // Print the error message
http.Error(w, e.Message+"\n"+e.Error.Error(), e.Code) // Serve a generic error message if the file isn't cached and doesn't exist
}
}
}
}