Skip to content

Commit 6e5e397

Browse files
authored
Optionally allow for SSL (#4)
Optionally allow for SSL listener.
1 parent 4c973e1 commit 6e5e397

File tree

9 files changed

+174
-41
lines changed

9 files changed

+174
-41
lines changed

.codecov.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ coverage:
1313
patch: yes
1414
changes: no
1515

16-
comment:
17-
layout: header, changes, diff, sunburst
18-
behavior: default
19-
require_changes: no
16+
comment: off
2017

2118
ignore:
2219
- "vendor/*"

README.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
3030
## Installation
3131

32-
`serve` can be installed in a handeful of ways:
32+
`serve` can be installed in a handful of ways:
3333

3434
### Homebrew on macOS
3535

@@ -58,17 +58,24 @@ To build from source, check out the instructions on getting started with
5858

5959
## Usage
6060

61-
Run a server from the current directory:
62-
6361
```sh
64-
serve
62+
serve [options] [path]
6563
```
6664

67-
Or, specify the directory. Paths can be both relative and absolute:
65+
> `[path]` defaults to `.` (relative path to the current directory)
6866
69-
```sh
70-
serve /var/www # or serve -dir=/var/www
71-
```
67+
Then simply open your browser to http://localhost:8080 to view your server.
68+
69+
### Options
70+
71+
The following configuration options are available:
72+
73+
* `--host` host address to bind to (defaults to `0.0.0.0`)
74+
* `--port` listening port (defaults to `8080`)
75+
* `--ssl` enable https (defaults to `false`)
76+
* `--cert` path to the ssl cert file (defaults to `cert.pem`)
77+
* `--key` path to the ssl key file (defaults to `key.pem`)
78+
* `--dir` directory path to serve (defaults to `.`, also configurable by `arg[0]`)
7279

7380
## Development
7481

cmd/serve/main.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ var version = "0.0.0-develop"
1414

1515
func main() {
1616
var opt config.Flags
17-
flag.StringVar(&opt.Host, "host", "", "host address to bind to")
17+
flag.StringVar(&opt.Host, "host", "0.0.0.0", "host address to bind to")
1818
flag.IntVar(&opt.Port, "port", 8080, "listening port")
19-
flag.StringVar(&opt.Dir, "dir", "", "directory to serve")
19+
flag.BoolVar(&opt.EnableSSL, "ssl", false, "enable https")
20+
flag.StringVar(&opt.CertFile, "cert", "cert.pem", "path to the ssl cert file")
21+
flag.StringVar(&opt.KeyFile, "key", "key.pem", "path to the ssl key file")
22+
flag.StringVar(&opt.Directory, "dir", "", "directory path to serve")
2023
flag.Parse()
2124

2225
log := log.New(os.Stderr, "[serve] ", log.LstdFlags)
2326

2427
cmd := flag.Arg(0)
2528

26-
dir, err := config.SanitizeDir(opt.Dir, cmd)
29+
dir, err := config.SanitizeDir(opt.Directory, cmd)
2730
if err != nil {
28-
log.Printf("sanitize dir: %v", err)
31+
log.Printf("sanitize directory: %v", err)
2932
os.Exit(1)
3033
}
3134

fixtures/cert.pem

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEIDCCAwigAwIBAgIUG4x9A3w/n65jwz3y7Wo8MDrU6QEwDQYJKoZIhvcNAQEL
3+
BQAweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9y
4+
azEVMBMGA1UECgwMRXhhbXBsZSwgTExDMRIwEAYDVQQDDAlzaXRlLnRlc3QxHzAd
5+
BgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTkwMTE3MTA0NDM0WhcN
6+
MjAwMTE3MTA0NDM0WjB5MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxETAPBgNV
7+
BAcMCE5ldyBZb3JrMRUwEwYDVQQKDAxFeGFtcGxlLCBMTEMxEjAQBgNVBAMMCXNp
8+
dGUudGVzdDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCCASIwDQYJ
9+
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALLlVETDAxfpbMrL9vlTKu2y+G8y7qNv
10+
KIdp5FllHAtZVPMis1xV9U4xvpy7baKTKKPtKEYZGcy/gW4fEN9KlvHZSUqrLj7T
11+
X0ySTNkwGItZy+gm1gbwvbQGtL4atgu0jPsJB662DIzq4dLL1OAFMV6VfmY9r2Hs
12+
ARhe0XjGtXKlX+Fyqnbxsot02C01CtFDcEftHR5KUZeUHkoIHmO+5ZtRAgAIfhV/
13+
DQfyn+GfXOfM7PWGfy7RdyyLMrD+SwdfJFpkeeqQTi7p3PIIuHmieGOBjIOUhRv2
14+
IEA7PbMNwoernE3Ey6iwErPjshWhSdLFG4NfAPs/KxDKe0qByRLOfZECAwEAAaOB
15+
nzCBnDAdBgNVHQ4EFgQUWlS44ZoMP/8IkJhHwxzJcfZ7IuIwHwYDVR0jBBgwFoAU
16+
WlS44ZoMP/8IkJhHwxzJcfZ7IuIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwFAYD
17+
VR0RBA0wC4IJc2l0ZS50ZXN0MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy
18+
YXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEASQ/wPIrRSsIEewDg
19+
t6dehznWR+iBMGWGMpDEVw/IpRSN1zxLJp3i/4Yjcr98bEIP4tW27OODSJSKz11R
20+
6/Kb/B04g3s7N4iSAehpeQXPGktNlgGojZSXi7u2y5ON6QBAle5csFxIkuOWDVwH
21+
qM/lsVlNHGyM0BGVMm5VLi2OWSqspz6Lr6yguT7U/AJ/hPe+YjSU5Kc+OnCZ4IH0
22+
NcdVG5aPpDFeZ7c9v1uHa7b725lyXUYO8xfWR3QV6CsTLgRFWhwYBXF51sZbBBsr
23+
fu78txegVWnYau4uh/nytqPoOnjoP4BAMKlynPfIpJ9TLWxosWeXro2xY5zvdFkp
24+
XH/+0g==
25+
-----END CERTIFICATE-----

fixtures/key.pem

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCy5VREwwMX6WzK
3+
y/b5UyrtsvhvMu6jbyiHaeRZZRwLWVTzIrNcVfVOMb6cu22ikyij7ShGGRnMv4Fu
4+
HxDfSpbx2UlKqy4+019MkkzZMBiLWcvoJtYG8L20BrS+GrYLtIz7CQeutgyM6uHS
5+
y9TgBTFelX5mPa9h7AEYXtF4xrVypV/hcqp28bKLdNgtNQrRQ3BH7R0eSlGXlB5K
6+
CB5jvuWbUQIACH4Vfw0H8p/hn1znzOz1hn8u0XcsizKw/ksHXyRaZHnqkE4u6dzy
7+
CLh5onhjgYyDlIUb9iBAOz2zDcKHq5xNxMuosBKz47IVoUnSxRuDXwD7PysQyntK
8+
gckSzn2RAgMBAAECggEBAIJ5/q80KHJtPnrermAER6AcU1QPKrwq271//xswQncI
9+
jYvTeEvVKdgBMgvwK7NSb2a4FxKhRg7ucgEWSWECbvsvxmPeXBlYYv5fCguyJ4Sj
10+
VrQYdyuStFm0Nmkc5D+/TL/fQyoq/xZcTZ5IKhfF0c8xa4I4ZU0fK2FR7qePDlHx
11+
kAjInhIAPxCh7vhKk35duhr8r7IDQ33jVyPQ7DgsEIKRh85CVxkcwrtV1sY3LM/O
12+
xmrYWxHzpke06qZBJROjAFKv1kV7NT3eKzgKg16yDkFqYdh38RnFsTB6/zgZ+rko
13+
Jj23tynefYRx3e3feAvhnDQzY32HwKCA4fNm0brJrf0CgYEA7cdXzN0QLwvhvjem
14+
t0gNdcfk0f9pM0wcYh0n7ESANsKAkjAOBqlvJ6tRV1LaqeIX+y1yeBnUIVH+dNfA
15+
tM2nTiilvaasR1Er40c3eeyIhWJ8nC+wBGexxDg3Ys4B0azzcakCYkG6BuVdsAWD
16+
aYdqWf6Tl80l7HwonCVFsu8nX+cCgYEAwJrX3agdZWTuAcFcdGIXWK1m8+4yGv6t
17+
fvwh9X/rkDQHJ5HXDsHmTc8yh/Qa35OzcZJxBooW5azmzVpEbgE/HjnBpNDjp0VT
18+
Xk5k+bZkWgp6wN8BFrh2Me8hliRs93vsUZ+fnFJWgxMTPMpOvhcw9YjucG6lGpwk
19+
ynGkJ0/bZ8cCgYAs8hVioBbDDdfqANL+qhwBO3vBRio4jBaBZUl6m6gwsatj9rlw
20+
AO8F7Jg/jWXP3vDxhbGxihBTDBCxPWcrxgPt/jj2FF9US7+kAn42CcP0kp1DWLBI
21+
5ODxWj796jrly29o+K1+rTXgv9Jpx2EDvZkY0cpMU3brsLxsZ485N4OV2QKBgQCV
22+
G0rinrOjO2/GjBs3Pnk0fYmmblD79Q37sNXZaR7ElIK1b4I+On5A3pcQCTqEu6O/
23+
2M8HcQAo7qH/eFJhlzV2AOCY595WMKVJ7QbfCwTFcDd3+Syumj9miOpHgguZzKY2
24+
yoyWSGgRMUNDXJt5LhsI+ukcwYuv/hG9aBzdEkWZIQKBgGLj5nwaJZWPJ381adJX
25+
JhwQcnS7cZIKrAifCay1oOaOcdQq/07QdBEjR6YT/X7oZCPtiDOdat9vzWKLNEY/
26+
nYY+XFijSz2CKvT+CScjJSxmrsCtiNBQRtaTSKWAcgCpSqN5S+mocWmInZBVtZev
27+
1OueDMUyPAsCabIR4HiTgAIs
28+
-----END PRIVATE KEY-----

internal/commands/server.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@ import (
1212
"github.com/syntaqx/serve/internal/middleware"
1313
)
1414

15+
var getHTTPServerFunc = GetStdHTTPServer
16+
17+
// HTTPServer defines a returnable interface type for http.Server
18+
type HTTPServer interface {
19+
ListenAndServe() error
20+
ListenAndServeTLS(certFile, keyFile string) error
21+
}
22+
23+
// GetStdHTTPServer
24+
func GetStdHTTPServer(addr string, h http.Handler) HTTPServer {
25+
return &http.Server{
26+
Addr: addr,
27+
Handler: h,
28+
ReadTimeout: 15 * time.Second,
29+
WriteTimeout: 15 * time.Second,
30+
}
31+
}
32+
1533
// Server implements the static http server command.
1634
func Server(log *log.Logger, opt config.Flags, dir string) error {
1735
fs := serve.NewFileServer(serve.Options{
@@ -24,13 +42,14 @@ func Server(log *log.Logger, opt config.Flags, dir string) error {
2442
middleware.CORS(),
2543
)
2644

27-
server := &http.Server{
28-
Addr: net.JoinHostPort(opt.Host, strconv.Itoa(opt.Port)),
29-
Handler: fs,
30-
ReadTimeout: 15 * time.Second,
31-
WriteTimeout: 15 * time.Second,
45+
addr := net.JoinHostPort(opt.Host, strconv.Itoa(opt.Port))
46+
server := getHTTPServerFunc(addr, fs)
47+
48+
if opt.EnableSSL {
49+
log.Printf("https server listening at %s", addr)
50+
return server.ListenAndServeTLS(opt.CertFile, opt.KeyFile)
3251
}
3352

34-
log.Printf("http server listening at %s", server.Addr)
53+
log.Printf("http server listening at %s", addr)
3554
return server.ListenAndServe()
3655
}

internal/commands/server_test.go

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,68 @@ import (
99

1010
"github.com/stretchr/testify/assert"
1111
"github.com/syntaqx/serve/internal/config"
12+
"github.com/syntaqx/serve/mock"
1213
)
1314

15+
func getMockHTTPServerFunc(shouldError bool) func(addr string, h http.Handler) HTTPServer {
16+
return func(addr string, h http.Handler) HTTPServer {
17+
return &mock.HTTPServer{ShouldError: shouldError}
18+
}
19+
}
20+
21+
func TestGetStdHTTPServer(t *testing.T) {
22+
_, ok := GetStdHTTPServer("", http.DefaultServeMux).(*http.Server)
23+
assert.True(t, ok)
24+
}
25+
1426
func TestServer(t *testing.T) {
15-
t.Parallel()
27+
getHTTPServerFunc = getMockHTTPServerFunc(false)
28+
1629
assert := assert.New(t)
1730

1831
var b bytes.Buffer
1932
log := log.New(&b, "[test] ", 0)
20-
opt := config.Flags{Port: 0}
33+
opt := config.Flags{}
2134

22-
go func() {
23-
assert.NoError(Server(log, opt, "."))
24-
}()
35+
assert.NoError(Server(log, opt, "."))
36+
assert.Contains(b.String(), "http server listening at")
2537

26-
time.Sleep(200 * time.Millisecond)
38+
getHTTPServerFunc = GetStdHTTPServer
2739
}
2840

2941
func TestServerErr(t *testing.T) {
30-
t.Parallel()
42+
getHTTPServerFunc = getMockHTTPServerFunc(true)
43+
3144
assert := assert.New(t)
3245

3346
var b bytes.Buffer
34-
log := log.New(&b, "[test] ", 8888)
35-
opt := config.Flags{Port: 8888}
47+
log := log.New(&b, "[test] ", 0)
48+
opt := config.Flags{}
3649

37-
go func() {
38-
_ = http.ListenAndServe(":8888", nil)
39-
}()
50+
time.Sleep(200 * time.Millisecond)
4051

52+
assert.Error(Server(log, opt, "."))
4153
time.Sleep(200 * time.Millisecond)
4254

43-
go func() {
44-
assert.Error(Server(log, opt, "."))
45-
}()
55+
getHTTPServerFunc = GetStdHTTPServer
56+
}
4657

47-
time.Sleep(200 * time.Millisecond)
58+
func TestServerHTTPS(t *testing.T) {
59+
getHTTPServerFunc = getMockHTTPServerFunc(false)
60+
61+
assert := assert.New(t)
62+
63+
var b bytes.Buffer
64+
log := log.New(&b, "[test] ", 0)
65+
66+
opt := config.Flags{
67+
EnableSSL: true,
68+
CertFile: "../../fixtures/cert.pem",
69+
KeyFile: "../../fixtures/key.pem",
70+
}
71+
72+
assert.NoError(Server(log, opt, "."))
73+
assert.Contains(b.String(), "https server listening at")
74+
75+
getHTTPServerFunc = GetStdHTTPServer
4876
}

internal/config/flags.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ var getwd = os.Getwd
99

1010
// Flags are the expose configuration flags available to the serve binary.
1111
type Flags struct {
12-
Host string
13-
Port int
14-
Dir string
12+
Host string
13+
Port int
14+
EnableSSL bool
15+
CertFile string
16+
KeyFile string
17+
Directory string
1518
}
1619

1720
// SanitizeDir allows a directory source to be set from multiple values. If any

mock/http.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package mock
2+
3+
import "errors"
4+
5+
var ErrMock = errors.New("mock error")
6+
7+
type HTTPServer struct {
8+
ShouldError bool
9+
}
10+
11+
func (s *HTTPServer) ListenAndServe() error {
12+
if s.ShouldError {
13+
return ErrMock
14+
}
15+
return nil
16+
}
17+
18+
func (s *HTTPServer) ListenAndServeTLS(certFile, keyFile string) error {
19+
if s.ShouldError {
20+
return ErrMock
21+
}
22+
return nil
23+
}

0 commit comments

Comments
 (0)