-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathhttpserver.go
More file actions
147 lines (128 loc) · 3.48 KB
/
httpserver.go
File metadata and controls
147 lines (128 loc) · 3.48 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package httpserver
import (
"crypto/tls"
"errors"
"net/http"
"os"
"path/filepath"
"github.com/projectdiscovery/sslcert"
)
// Options of the http server
type Options struct {
Folder string
EnableUpload bool
LogUA bool // enable logging user agent
ListenAddress string
TLS bool
Certificate string
CertificateKey string
CertificateDomain string
BasicAuthUsername string
BasicAuthPassword string
BasicAuthReal string
Verbose bool
Sandbox bool
HTTP1Only bool
MaxFileSize int // 50Mb
MaxDumpBodySize int64
Python bool
CORS bool
HTTPHeaders []HTTPHeader
JSONLogFile string
}
// HTTPServer instance
type HTTPServer struct {
options *Options
layers http.Handler
jsonLogger *JSONLogger
}
// LayerHandler is the interface of all layer funcs
type Middleware func(http.Handler) http.Handler
// New http server instance with options
func New(options *Options) (*HTTPServer, error) {
var h HTTPServer
EnableUpload = options.EnableUpload
EnableVerbose = options.Verbose
EnableLogUA = options.LogUA
// Initialize JSON logger if specified
if options.JSONLogFile != "" {
jsonLogger, err := NewJSONLogger(options.JSONLogFile)
if err != nil {
return nil, err
}
h.jsonLogger = jsonLogger
}
folder, err := filepath.Abs(options.Folder)
if err != nil {
return nil, err
}
if _, err := os.Stat(folder); os.IsNotExist(err) {
return nil, errors.New("path does not exist")
}
options.Folder = folder
var dir http.FileSystem
dir = http.Dir(options.Folder)
if options.Sandbox {
dir = SandboxFileSystem{fs: http.Dir(options.Folder), RootFolder: options.Folder}
}
var httpHandler http.Handler
if options.Python {
httpHandler = PythonStyle(dir.(http.Dir))
} else {
httpHandler = http.FileServer(dir)
}
addHandler := func(newHandler Middleware) {
httpHandler = newHandler(httpHandler)
}
// middleware
if options.EnableUpload {
addHandler(h.uploadlayer)
}
if options.BasicAuthUsername != "" || options.BasicAuthPassword != "" {
addHandler(h.basicauthlayer)
}
if options.CORS {
addHandler(h.corslayer)
}
httpHandler = h.loglayer(httpHandler)
httpHandler = h.headerlayer(httpHandler, options.HTTPHeaders)
// add handler
h.layers = httpHandler
h.options = options
return &h, nil
}
func (t *HTTPServer) makeHTTPServer(tlsConfig *tls.Config) *http.Server {
httpServer := &http.Server{Addr: t.options.ListenAddress}
if t.options.HTTP1Only {
httpServer.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
}
httpServer.TLSConfig = tlsConfig
httpServer.Handler = t.layers
return httpServer
}
// ListenAndServe requests over http
func (t *HTTPServer) ListenAndServe() error {
httpServer := t.makeHTTPServer(nil)
return httpServer.ListenAndServe()
}
// ListenAndServeTLS requests over https
func (t *HTTPServer) ListenAndServeTLS() error {
if t.options.Certificate == "" || t.options.CertificateKey == "" {
tlsOptions := sslcert.DefaultOptions
tlsOptions.Host = t.options.CertificateDomain
tlsConfig, err := sslcert.NewTLSConfig(tlsOptions)
if err != nil {
return err
}
httpServer := t.makeHTTPServer(tlsConfig)
return httpServer.ListenAndServeTLS("", "")
}
return http.ListenAndServeTLS(t.options.ListenAddress, t.options.Certificate, t.options.CertificateKey, t.layers)
}
// Close the service
func (t *HTTPServer) Close() error {
if t.jsonLogger != nil {
return t.jsonLogger.Close()
}
return nil
}