Merged Proxy with dumb-http command
parent
b1685c39cf
commit
d144cfdabe
2
LICENSE
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:
|
||||
|
||||
|
|
107
README.md
107
README.md
|
@ -1,23 +1,110 @@
|
|||
# dumb-http
|
||||
## Simple HTTP Server
|
||||
Simple HTTP Server and single host 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, Nginx and Apache, they should be preferred
|
||||
over this. For development usecase, certianly 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
|
||||
|
||||
> Reference: https://gist.github.com/cespare/3985516
|
||||
To enable API access at path /api/ and pass the request to upstream. Also / serves the static files
|
||||
from `-path` mentioned.
|
||||
|
||||
## LICENSE
|
||||
|
||||
```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)
|
||||
|
||||
|
||||
# LICENSE
|
||||
|
||||
MIT
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -14,6 +14,13 @@ type Proxy struct {
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -26,6 +33,10 @@ func New(upstream, root string) (*Proxy, error) {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
Loading…
Reference in New Issue