Skip to content

Commit

Permalink
Optionally allow for SSL (#4)
Browse files Browse the repository at this point in the history
Optionally allow for SSL listener.
  • Loading branch information
syntaqx committed Jan 17, 2019
1 parent 4c973e1 commit 6e5e397
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 41 deletions.
5 changes: 1 addition & 4 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ coverage:
patch: yes
changes: no

comment:
layout: header, changes, diff, sunburst
behavior: default
require_changes: no
comment: off

ignore:
- "vendor/*"
Expand Down
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
## Installation

`serve` can be installed in a handeful of ways:
`serve` can be installed in a handful of ways:

### Homebrew on macOS

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

## Usage

Run a server from the current directory:

```sh
serve
serve [options] [path]
```

Or, specify the directory. Paths can be both relative and absolute:
> `[path]` defaults to `.` (relative path to the current directory)
```sh
serve /var/www # or serve -dir=/var/www
```
Then simply open your browser to http://localhost:8080 to view your server.

### Options

The following configuration options are available:

* `--host` host address to bind to (defaults to `0.0.0.0`)
* `--port` listening port (defaults to `8080`)
* `--ssl` enable https (defaults to `false`)
* `--cert` path to the ssl cert file (defaults to `cert.pem`)
* `--key` path to the ssl key file (defaults to `key.pem`)
* `--dir` directory path to serve (defaults to `.`, also configurable by `arg[0]`)

## Development

Expand Down
11 changes: 7 additions & 4 deletions cmd/serve/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ var version = "0.0.0-develop"

func main() {
var opt config.Flags
flag.StringVar(&opt.Host, "host", "", "host address to bind to")
flag.StringVar(&opt.Host, "host", "0.0.0.0", "host address to bind to")
flag.IntVar(&opt.Port, "port", 8080, "listening port")
flag.StringVar(&opt.Dir, "dir", "", "directory to serve")
flag.BoolVar(&opt.EnableSSL, "ssl", false, "enable https")
flag.StringVar(&opt.CertFile, "cert", "cert.pem", "path to the ssl cert file")
flag.StringVar(&opt.KeyFile, "key", "key.pem", "path to the ssl key file")
flag.StringVar(&opt.Directory, "dir", "", "directory path to serve")
flag.Parse()

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

cmd := flag.Arg(0)

dir, err := config.SanitizeDir(opt.Dir, cmd)
dir, err := config.SanitizeDir(opt.Directory, cmd)
if err != nil {
log.Printf("sanitize dir: %v", err)
log.Printf("sanitize directory: %v", err)
os.Exit(1)
}

Expand Down
25 changes: 25 additions & 0 deletions fixtures/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEIDCCAwigAwIBAgIUG4x9A3w/n65jwz3y7Wo8MDrU6QEwDQYJKoZIhvcNAQEL
BQAweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9y
azEVMBMGA1UECgwMRXhhbXBsZSwgTExDMRIwEAYDVQQDDAlzaXRlLnRlc3QxHzAd
BgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTkwMTE3MTA0NDM0WhcN
MjAwMTE3MTA0NDM0WjB5MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxETAPBgNV
BAcMCE5ldyBZb3JrMRUwEwYDVQQKDAxFeGFtcGxlLCBMTEMxEjAQBgNVBAMMCXNp
dGUudGVzdDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALLlVETDAxfpbMrL9vlTKu2y+G8y7qNv
KIdp5FllHAtZVPMis1xV9U4xvpy7baKTKKPtKEYZGcy/gW4fEN9KlvHZSUqrLj7T
X0ySTNkwGItZy+gm1gbwvbQGtL4atgu0jPsJB662DIzq4dLL1OAFMV6VfmY9r2Hs
ARhe0XjGtXKlX+Fyqnbxsot02C01CtFDcEftHR5KUZeUHkoIHmO+5ZtRAgAIfhV/
DQfyn+GfXOfM7PWGfy7RdyyLMrD+SwdfJFpkeeqQTi7p3PIIuHmieGOBjIOUhRv2
IEA7PbMNwoernE3Ey6iwErPjshWhSdLFG4NfAPs/KxDKe0qByRLOfZECAwEAAaOB
nzCBnDAdBgNVHQ4EFgQUWlS44ZoMP/8IkJhHwxzJcfZ7IuIwHwYDVR0jBBgwFoAU
WlS44ZoMP/8IkJhHwxzJcfZ7IuIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwFAYD
VR0RBA0wC4IJc2l0ZS50ZXN0MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy
YXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEASQ/wPIrRSsIEewDg
t6dehznWR+iBMGWGMpDEVw/IpRSN1zxLJp3i/4Yjcr98bEIP4tW27OODSJSKz11R
6/Kb/B04g3s7N4iSAehpeQXPGktNlgGojZSXi7u2y5ON6QBAle5csFxIkuOWDVwH
qM/lsVlNHGyM0BGVMm5VLi2OWSqspz6Lr6yguT7U/AJ/hPe+YjSU5Kc+OnCZ4IH0
NcdVG5aPpDFeZ7c9v1uHa7b725lyXUYO8xfWR3QV6CsTLgRFWhwYBXF51sZbBBsr
fu78txegVWnYau4uh/nytqPoOnjoP4BAMKlynPfIpJ9TLWxosWeXro2xY5zvdFkp
XH/+0g==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions fixtures/key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCy5VREwwMX6WzK
y/b5UyrtsvhvMu6jbyiHaeRZZRwLWVTzIrNcVfVOMb6cu22ikyij7ShGGRnMv4Fu
HxDfSpbx2UlKqy4+019MkkzZMBiLWcvoJtYG8L20BrS+GrYLtIz7CQeutgyM6uHS
y9TgBTFelX5mPa9h7AEYXtF4xrVypV/hcqp28bKLdNgtNQrRQ3BH7R0eSlGXlB5K
CB5jvuWbUQIACH4Vfw0H8p/hn1znzOz1hn8u0XcsizKw/ksHXyRaZHnqkE4u6dzy
CLh5onhjgYyDlIUb9iBAOz2zDcKHq5xNxMuosBKz47IVoUnSxRuDXwD7PysQyntK
gckSzn2RAgMBAAECggEBAIJ5/q80KHJtPnrermAER6AcU1QPKrwq271//xswQncI
jYvTeEvVKdgBMgvwK7NSb2a4FxKhRg7ucgEWSWECbvsvxmPeXBlYYv5fCguyJ4Sj
VrQYdyuStFm0Nmkc5D+/TL/fQyoq/xZcTZ5IKhfF0c8xa4I4ZU0fK2FR7qePDlHx
kAjInhIAPxCh7vhKk35duhr8r7IDQ33jVyPQ7DgsEIKRh85CVxkcwrtV1sY3LM/O
xmrYWxHzpke06qZBJROjAFKv1kV7NT3eKzgKg16yDkFqYdh38RnFsTB6/zgZ+rko
Jj23tynefYRx3e3feAvhnDQzY32HwKCA4fNm0brJrf0CgYEA7cdXzN0QLwvhvjem
t0gNdcfk0f9pM0wcYh0n7ESANsKAkjAOBqlvJ6tRV1LaqeIX+y1yeBnUIVH+dNfA
tM2nTiilvaasR1Er40c3eeyIhWJ8nC+wBGexxDg3Ys4B0azzcakCYkG6BuVdsAWD
aYdqWf6Tl80l7HwonCVFsu8nX+cCgYEAwJrX3agdZWTuAcFcdGIXWK1m8+4yGv6t
fvwh9X/rkDQHJ5HXDsHmTc8yh/Qa35OzcZJxBooW5azmzVpEbgE/HjnBpNDjp0VT
Xk5k+bZkWgp6wN8BFrh2Me8hliRs93vsUZ+fnFJWgxMTPMpOvhcw9YjucG6lGpwk
ynGkJ0/bZ8cCgYAs8hVioBbDDdfqANL+qhwBO3vBRio4jBaBZUl6m6gwsatj9rlw
AO8F7Jg/jWXP3vDxhbGxihBTDBCxPWcrxgPt/jj2FF9US7+kAn42CcP0kp1DWLBI
5ODxWj796jrly29o+K1+rTXgv9Jpx2EDvZkY0cpMU3brsLxsZ485N4OV2QKBgQCV
G0rinrOjO2/GjBs3Pnk0fYmmblD79Q37sNXZaR7ElIK1b4I+On5A3pcQCTqEu6O/
2M8HcQAo7qH/eFJhlzV2AOCY595WMKVJ7QbfCwTFcDd3+Syumj9miOpHgguZzKY2
yoyWSGgRMUNDXJt5LhsI+ukcwYuv/hG9aBzdEkWZIQKBgGLj5nwaJZWPJ381adJX
JhwQcnS7cZIKrAifCay1oOaOcdQq/07QdBEjR6YT/X7oZCPtiDOdat9vzWKLNEY/
nYY+XFijSz2CKvT+CScjJSxmrsCtiNBQRtaTSKWAcgCpSqN5S+mocWmInZBVtZev
1OueDMUyPAsCabIR4HiTgAIs
-----END PRIVATE KEY-----
31 changes: 25 additions & 6 deletions internal/commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ import (
"github.com/syntaqx/serve/internal/middleware"
)

var getHTTPServerFunc = GetStdHTTPServer

// HTTPServer defines a returnable interface type for http.Server
type HTTPServer interface {
ListenAndServe() error
ListenAndServeTLS(certFile, keyFile string) error
}

// GetStdHTTPServer
func GetStdHTTPServer(addr string, h http.Handler) HTTPServer {
return &http.Server{
Addr: addr,
Handler: h,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
}
}

// Server implements the static http server command.
func Server(log *log.Logger, opt config.Flags, dir string) error {
fs := serve.NewFileServer(serve.Options{
Expand All @@ -24,13 +42,14 @@ func Server(log *log.Logger, opt config.Flags, dir string) error {
middleware.CORS(),
)

server := &http.Server{
Addr: net.JoinHostPort(opt.Host, strconv.Itoa(opt.Port)),
Handler: fs,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
addr := net.JoinHostPort(opt.Host, strconv.Itoa(opt.Port))
server := getHTTPServerFunc(addr, fs)

if opt.EnableSSL {
log.Printf("https server listening at %s", addr)
return server.ListenAndServeTLS(opt.CertFile, opt.KeyFile)
}

log.Printf("http server listening at %s", server.Addr)
log.Printf("http server listening at %s", addr)
return server.ListenAndServe()
}
60 changes: 44 additions & 16 deletions internal/commands/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,68 @@ import (

"github.com/stretchr/testify/assert"
"github.com/syntaqx/serve/internal/config"
"github.com/syntaqx/serve/mock"
)

func getMockHTTPServerFunc(shouldError bool) func(addr string, h http.Handler) HTTPServer {
return func(addr string, h http.Handler) HTTPServer {
return &mock.HTTPServer{ShouldError: shouldError}
}
}

func TestGetStdHTTPServer(t *testing.T) {
_, ok := GetStdHTTPServer("", http.DefaultServeMux).(*http.Server)
assert.True(t, ok)
}

func TestServer(t *testing.T) {
t.Parallel()
getHTTPServerFunc = getMockHTTPServerFunc(false)

assert := assert.New(t)

var b bytes.Buffer
log := log.New(&b, "[test] ", 0)
opt := config.Flags{Port: 0}
opt := config.Flags{}

go func() {
assert.NoError(Server(log, opt, "."))
}()
assert.NoError(Server(log, opt, "."))
assert.Contains(b.String(), "http server listening at")

time.Sleep(200 * time.Millisecond)
getHTTPServerFunc = GetStdHTTPServer
}

func TestServerErr(t *testing.T) {
t.Parallel()
getHTTPServerFunc = getMockHTTPServerFunc(true)

assert := assert.New(t)

var b bytes.Buffer
log := log.New(&b, "[test] ", 8888)
opt := config.Flags{Port: 8888}
log := log.New(&b, "[test] ", 0)
opt := config.Flags{}

go func() {
_ = http.ListenAndServe(":8888", nil)
}()
time.Sleep(200 * time.Millisecond)

assert.Error(Server(log, opt, "."))
time.Sleep(200 * time.Millisecond)

go func() {
assert.Error(Server(log, opt, "."))
}()
getHTTPServerFunc = GetStdHTTPServer
}

time.Sleep(200 * time.Millisecond)
func TestServerHTTPS(t *testing.T) {
getHTTPServerFunc = getMockHTTPServerFunc(false)

assert := assert.New(t)

var b bytes.Buffer
log := log.New(&b, "[test] ", 0)

opt := config.Flags{
EnableSSL: true,
CertFile: "../../fixtures/cert.pem",
KeyFile: "../../fixtures/key.pem",
}

assert.NoError(Server(log, opt, "."))
assert.Contains(b.String(), "https server listening at")

getHTTPServerFunc = GetStdHTTPServer
}
9 changes: 6 additions & 3 deletions internal/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ var getwd = os.Getwd

// Flags are the expose configuration flags available to the serve binary.
type Flags struct {
Host string
Port int
Dir string
Host string
Port int
EnableSSL bool
CertFile string
KeyFile string
Directory string
}

// SanitizeDir allows a directory source to be set from multiple values. If any
Expand Down
23 changes: 23 additions & 0 deletions mock/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package mock

import "errors"

var ErrMock = errors.New("mock error")

type HTTPServer struct {
ShouldError bool
}

func (s *HTTPServer) ListenAndServe() error {
if s.ShouldError {
return ErrMock
}
return nil
}

func (s *HTTPServer) ListenAndServeTLS(certFile, keyFile string) error {
if s.ShouldError {
return ErrMock
}
return nil
}

0 comments on commit 6e5e397

Please sign in to comment.