Browse Source

Merge pull request 'Feature added: dumb-proxy' (#2) from dumb-proxy into master

Reviewed-on: https://git.dcpri.me/some-fancy-tools/dumb-http/pulls/2
master v2.1.0
Darshil Chanpura 4 months ago
parent
commit
9ca8debd2f
  1. 103
      .drone.yml
  2. 2
      LICENSE
  3. 5
      Makefile
  4. 106
      README.md
  5. 51
      cmd/dumb-http/main.go
  6. 39
      cmd/dumb-proxy/main.go
  7. 8
      go.mod
  8. 25
      go.sum
  9. 30
      logger/log_handler.go
  10. 57
      proxy/proxy.go

103
.drone.yml

@ -0,0 +1,103 @@
---
kind: pipeline
type: docker
name: default
platform:
os: linux
arch: amd64
workspace:
path: /drone/src
steps:
- name: prerequisites
image: golang
commands:
- mkdir -p release
- go install honnef.co/go/tools/cmd/staticcheck@latest
- go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
volumes:
- name: cache
path: /go
- name: test
image: golang
commands:
- go test -v -race ./...
- go vet ./...
- staticcheck ./...
- gocyclo -over 19 $(find . -iname '*.go' -type f | grep -v /vendor/)
volumes:
- name: cache
path: /go
depends_on:
- prerequisites
- name: build-darwin
image: golang
commands:
- mkdir -p release/darwin
- GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o release/darwin/dumb-http cmd/dumb-http/main.go
- tar -czf release/dumb-http-${DRONE_TAG:-latest}-darwin-amd64.tar.gz README.md -C release/darwin/ dumb-http
- GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o release/darwin/dumb-http cmd/dumb-http/main.go
- tar -czf release/dumb-http-${DRONE_TAG:-latest}-darwin-arm64.tar.gz README.md -C release/darwin/ dumb-http
depends_on:
- test
when:
event:
- tag
- name: build-windows
image: golang
commands:
- mkdir -p release/windows
- GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o release/windows/dumb-http cmd/dumb-http/main.go
- tar -czf release/dumb-http-${DRONE_TAG:-latest}-windows-amd64.tar.gz README.md -C release/windows/ dumb-http
depends_on:
- test
when:
event:
- tag
- name: build-linux
image: golang
commands:
- mkdir -p release/linux
- GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o release/linux/dumb-http cmd/dumb-http/main.go
- tar -czf release/dumb-http-${DRONE_TAG:-latest}-linux-amd64.tar.gz README.md -C release/linux/ dumb-http
- GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o release/linux/dumb-http cmd/dumb-http/main.go
- tar -czf release/dumb-http-${DRONE_TAG:-latest}-linux-arm64.tar.gz README.md -C release/linux/ dumb-http
depends_on:
- test
when:
event:
- tag
- name: gitea-release
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_token
base_url: https://git.dcpri.me
checksum:
- sha256
files:
- release/*.tar.gz
title: Version ${DRONE_TAG/v/}
when:
event:
- tag
depends_on:
- build-linux
- build-darwin
- build-windows
volumes:
- name: cache
temp: {}
---
kind: signature
hmac: 0be535706d13718f51d54c7421346ace025f09cb6d1a7ab80650fff98453b4fa
...

2
LICENSE

@ -1,4 +1,4 @@
Copyright 2019-2020 Darshil Chanpura
Copyright 2019-2021 Darshil Chanpura
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

5
Makefile

@ -8,9 +8,8 @@ os = $(word 1, $@)
bootstrap:
@mkdir -p release
go get golang.org/x/lint # Linter
go get honnef.co/go/tools/cmd/staticcheck # Badass static analyzer/linter
go get github.com/fzipp/gocyclo # Cyclomatic complexity check
go install honnef.co/go/tools/cmd/staticcheck@latest # Badass static analyzer/linter
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest # Cyclomatic complexity check
test:
go test -v -race $(PKGS) # Normal Test

106
README.md

@ -1,23 +1,109 @@
# dumb-http
## Simple HTTP Server
Simple HTTP Server and an optional Single Host Reverse Proxy.
## Usage
This tool is useful to proxy to backend like an API and also serve static
content and avoid CORS Errors.
Though there's no harm is using this in Production, there are servers with
better implementation like [Caddy](https://caddyserver.com) and
[Nginx](https://nginx.org), they should be preferred over this. For development
usecase, certainly this is the best way to work with Single Page Frontend apps
and Backend APIs and avoid any CORS issues that slow down the development.
# Usage
```shell
$ dumb-http -h
Usage of dumb-http
-basic-auth-password string
Password for basic auth
-basic-auth-realm string
Realm for basic auth (default "DUMB-HTTP")
-basic-auth-username string
Username for basic auth
-host string
Host to listen on (default "0.0.0.0")
-path string
Path to serve from (default ".")
-port int
Port to listen on (default 8000)
-proxy-path string
Reverse Proxy path (default "/proxy/")
-proxy-strip-prefix
Strip Prefix while proxying
-proxy-upstream string
Reverse Proxy upstream (backend service). Proxy is disabled if empty
```
dumb-http [-path path-to-serve] [port]
```
### Example
```
# Examples
## Static Server
To quickly show some projects built that uses Javascript and calls a bunch of
APIs.
```shell
$ dumb-http -path ./docs
Serving at http://0.0.0.0:8000/ from ./docs
Serving with dumb-http/latest at http://0.0.0.0:8000/ from ./docs
Root Configuration: http://0.0.0.0:8000/ -> "./docs"
127.0.0.1 - - [06/Jul/2018 17:05:36] "GET / HTTP/1.1" 200 0 16.76µs "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0"
127.0.0.1 - - [06/Jul/2018 17:05:37] "GET / HTTP/1.1" 304 0 173ns "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0"
```
>Inspired by Python module http.server
## Static Server with Proxy
To enable API access at path /api/ and pass the request to upstream. Also / serves the static files
from `-path` mentioned.
```shell
$ dumb-http -path ./public -proxy-upstream http://127.0.0.1:8001 -proxy-path /api/
Serving with dumb-http/latest at http://0.0.0.0:8000/ from ./public
Root Configuration: http://0.0.0.0:8000/ -> "./public"
Proxy Configuration: http://0.0.0.0:8000/api/ -> http://127.0.0.1:8001/api/
```
In case if the Backend/Upstream doesn't have the path /api/ that is passed in
`-proxy-path` one can strip that and avoid it being passed to Backend/Upstream
using `-proxy-strip-prefix` that will change the behaviour accordingly.
```shell
$ dumb-http -path ./public -proxy-upstream http://127.0.0.1:8001 -proxy-path /api/ -proxy-strip-prefix
Serving with dumb-http/latest at http://0.0.0.0:8000/ from ./public
Root Configuration: http://0.0.0.0:8000/ -> "./public"
Proxy Configuration: http://0.0.0.0:8000/api/ -> http://127.0.0.1:8001
```
## Static Server with Basic Auth
In case if there's a need to add basic auth in the server, maybe sharing
something over a public network one can use the basic auth flags.
Basic auth needs username and password arguments `-basic-auth-username` and
`-basic-auth-password` respectively, once set this start serving and gives
error code 401 Unauthorized in case if the username and password is incorrect.
The first call will be a 401 as there are no credentials passed from Browser,
to ask for password the server sends `WWW-Authenticate` header as `Basic` with
realm which can be defined via another flag `-basic-auth-realm`. This asks for
password and subsequent requests work properly.
```shell
$ dumb-http -path ./docs -basic-auth-username john -basic-auth-password JohnDoe
Root Configuration: http://0.0.0.0:8000/ -> "./public"
127.0.0.1 - - [18/Sep/2021 10:41:09] "GET / HTTP/1.1" 401 0 34.641µs "-" "Mozilla/5.0 (X11; Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0"
```
> Note: The server does not have SSL Implemented yet, so eventually over a
public network the Authorization header can be sniffed, this means the
implementation is not secure by default.
# Acknowledgments
* Concept is inspired from Python module `http.server`.
* Go logging was implemented using snippet mentioned in this [GitHub Gist](https://gist.github.com/cespare/3985516)
> Reference: https://gist.github.com/cespare/3985516
## LICENSE
# LICENSE
MIT

51
cmd/dumb-http/main.go

@ -4,41 +4,48 @@ import (
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"git.dcpri.me/some-fancy-tools/dumb-http/logger"
"git.dcpri.me/some-fancy-tools/dumb-http/proxy"
)
var (
localDir = "."
host = "0.0.0.0"
version = "latest"
port = 8000
version = "latest"
localDir = flag.String("path", ".", "Path to serve from")
host = flag.String("host", "0.0.0.0", "Host to listen on")
port = flag.Int("port", 8000, "Port to listen on")
upstream = flag.String("proxy-upstream", "", "Reverse Proxy upstream (backend service). Proxy is disabled if empty")
proxyPath = flag.String("proxy-path", "/proxy/", "Reverse Proxy path")
stripPrefix = flag.Bool("proxy-strip-prefix", false, "Strip Prefix while proxying")
)
func init() {
flag.StringVar(&localDir, "path", ".", "Path to serve from")
flag.StringVar(&host, "host", "0.0.0.0", "Host to listen on")
flag.IntVar(&port, "port", 8000, "Port to listen on")
}
func main() {
flag.Parse()
// Start serving...
serve(fmt.Sprintf("%s:%d", host, port))
}
func serve(addr string) {
mux := http.NewServeMux()
// mux.HandleFunc("/testauth", SimpleAuth)
mux.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir(localDir))))
server := http.Server{
Addr: addr,
Handler: logger.NewLoggingHandler(mux, os.Stdout),
// initilize static server and proxy
p, err := proxy.New(*upstream, *localDir)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Serving with dumb-http/%s at http://%s/ from %s\n", version, addr, localDir)
err := server.ListenAndServe()
// initilize proxy routes and static server routes
p.Routes(*proxyPath, *stripPrefix)
addr := net.JoinHostPort(*host, fmt.Sprint(*port))
fmt.Printf("Serving with dumb-http/%s at http://%s/ from %s\n", version, addr, *localDir)
fmt.Printf(" Root Configuration: http://%s/ -> %q\n", addr, *localDir)
if *upstream != "" {
if *stripPrefix {
fmt.Printf("Proxy Configuration: http://%s%s -> %s\n", addr, *proxyPath, *upstream)
} else {
fmt.Printf("Proxy Configuration: http://%s%s -> %s%s\n", addr, *proxyPath, *upstream, *proxyPath)
}
}
err = http.ListenAndServe(addr, logger.NewLoggingHandler(p, os.Stdout))
if err != nil {
log.Fatal(err)
}

39
cmd/dumb-proxy/main.go

@ -0,0 +1,39 @@
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"git.dcpri.me/some-fancy-tools/dumb-http/logger"
"git.dcpri.me/some-fancy-tools/dumb-http/proxy"
)
var (
version = "latest"
addr = flag.String("addr", "127.0.0.1:8080", "Address")
root = flag.String("root", ".", "Document root to serve static files")
upstream = flag.String("upstream", "http://127.0.0.1:8081", "Reverse Proxy upstream (backend service)")
proxyPath = flag.String("proxy-path", "/proxy/", "Reverse Proxy path")
stripPrefix = flag.Bool("strip-prefix", false, "Strip Prefix while proxying")
)
func main() {
flag.Parse()
p, err := proxy.New(*upstream, *root)
if err != nil {
log.Fatal(err)
}
p.Routes(*proxyPath, *stripPrefix)
fmt.Printf("Serving with dumb-proxy/%s at http://%s \n", version, *addr)
fmt.Printf(" Root Configuration: http://%s/ -> %q\n", *addr, *root)
if *stripPrefix {
fmt.Printf("Proxy Configuration: http://%s%s -> %s\n", *addr, *proxyPath, *upstream)
} else {
fmt.Printf("Proxy Configuration: http://%s%s -> %s%s\n", *addr, *proxyPath, *upstream, *proxyPath)
}
http.ListenAndServe(*addr, logger.NewLoggingHandler(p, os.Stdout))
}

8
go.mod

@ -1,8 +1,10 @@
module git.dcpri.me/some-fancy-tools/dumb-http
go 1.14
go 1.17
require git.dcpri.me/modules/s3fs v1.0.0
require (
git.dcpri.me/modules/s3fs v1.0.0
github.com/aws/aws-sdk-go v1.33.1 // indirect
github.com/aws/aws-sdk-go v1.40.44 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
)

25
go.sum

@ -1,27 +1,34 @@
git.dcpri.me/modules/s3fs v1.0.0 h1:iivP7hz93acON2WVUy4xde80iOA0vTb4GQCROR2PO1k=
git.dcpri.me/modules/s3fs v1.0.0/go.mod h1:b6dBmk/TsF/Jhb9hs+/zD8QdyGrpD3xJzkiSzk7m3vo=
github.com/aws/aws-sdk-go v1.33.0 h1:Bq5Y6VTLbfnJp1IV8EL/qUU5qO1DYHda/zis/sqevkY=
github.com/aws/aws-sdk-go v1.33.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.33.1 h1:yz9XmNzPshz/lhfAZvLfMnIS9HPo8+boGRcWqDVX+T0=
github.com/aws/aws-sdk-go v1.33.1/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.40.44 h1:kECaYybTWYZY5IKHvQMxbE6Wi5Qrb+7hbkV7zQV3Sg8=
github.com/aws/aws-sdk-go v1.40.44/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

30
logger/log_handler.go

@ -11,17 +11,11 @@ import (
)
var (
realm string
user string
pass string
user = flag.String("basic-auth-username", "", "Username for basic auth")
pass = flag.String("basic-auth-password", "", "Password for basic auth")
realm = flag.String("basic-auth-realm", "DUMB-HTTP", "Realm for basic auth")
)
func init() {
flag.StringVar(&user, "username", "", "Username for basic auth")
flag.StringVar(&pass, "password", "", "Password for basic auth")
flag.StringVar(&realm, "realm", "DUMB-HTTP", "Realm for basic auth")
}
// LoggingHandler is to be used as wrapper of mux.
type LoggingHandler struct {
handler http.Handler
@ -71,11 +65,11 @@ func (h LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// For getting duration
// startTime := time.Now()
username, password, ok := r.BasicAuth()
if user == "" || pass == "" {
if *user == "" || *pass == "" {
successfulResponse(logRecord, h.handler, h.out, r)
return
}
if user != "" && pass != "" && (!ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1) {
if *user != "" && *pass != "" && (!ok || subtle.ConstantTimeCompare([]byte(*user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(*pass), []byte(password)) != 1) {
unsuccessfulResponse(logRecord, h.handler, h.out, w, r)
return
}
@ -83,22 +77,18 @@ func (h LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func successfulResponse(logRecord *LogRecord, h http.Handler, out io.Writer, r *http.Request) {
startTime := time.Now()
logRecord.time = time.Now()
h.ServeHTTP(logRecord, r)
endTime := time.Now()
logRecord.time = endTime.UTC()
logRecord.duration = endTime.Sub(startTime) / 1000.0
logRecord.duration = time.Since(logRecord.time)
logRecord.Log(out)
}
func unsuccessfulResponse(logRecord *LogRecord, h http.Handler, out io.Writer, w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
logRecord.time = time.Now()
w.Header().Set("WWW-Authenticate", `Basic realm="`+*realm+`"`)
logRecord.statusCode = http.StatusUnauthorized
w.WriteHeader(logRecord.statusCode)
fmt.Fprintln(w, "Unauthorized")
endTime := time.Now()
logRecord.time = endTime.UTC()
logRecord.duration = endTime.Sub(startTime) / 1000.0
logRecord.duration = time.Since(logRecord.time)
logRecord.Log(out)
}

57
proxy/proxy.go

@ -0,0 +1,57 @@
package proxy
import (
"net/http"
"net/http/httputil"
"net/url"
)
// Proxy struct contains the mux for handling paths, rp for conditionally
// doing a reverse proxy to upstream and root as root directory for serving
// static content.
type Proxy struct {
mux *http.ServeMux
rp *httputil.ReverseProxy
root string
}
// New will return a Proxy struct with a new server mux and
// set reverse proxy Proxy.rp in case if the upstream is not empty.
func New(upstream, root string) (*Proxy, error) {
if upstream == "" {
return &Proxy{
mux: http.NewServeMux(),
root: root,
}, nil
}
rpURL, err := url.Parse(upstream)
if err != nil {
return nil, err
}
return &Proxy{
mux: http.NewServeMux(),
rp: httputil.NewSingleHostReverseProxy(rpURL),
root: root,
}, nil
}
// Routes will set routes based on the values of Proxy.rp and
// by default set / to file server.
func (p *Proxy) Routes(proxyPath string, stripPrefix bool) {
if p.rp == nil {
p.mux.Handle("/", http.FileServer(http.Dir(p.root)))
return
}
if stripPrefix {
p.mux.Handle(proxyPath, http.StripPrefix(proxyPath, p.rp))
} else {
p.mux.Handle(proxyPath, p.rp)
}
p.mux.Handle("/", http.FileServer(http.Dir(p.root)))
}
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
p.mux.ServeHTTP(w, r)
}
Loading…
Cancel
Save