Please consider this sample Go code snippet,
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func main() {
listen_at := ":3114"
go http.Handle("/", http.FileServer(http.Dir(".")))
//go http.Handle("/max", http.FileServer(http.Dir("."))) <-- Fails
go http.HandleFunc("/ping", ping_handler)
log.Fatal(http.ListenAndServe(listen_at, nil))
}
func ping_handler(w http.ResponseWriter, r *http.Request) {
a := time.Now()
layout := "2006-01-02-03-04-05-000"
fmt.Println("Got root!")
fmt.Println("r is", r)
fmt.Println("RemoteAddr is", r.RemoteAddr)
send_this := "OK GOT ping! " + a.Format(layout)
w.Write([]byte(send_this))
}
I've two questions:
(1) How can I change the FileServer to serve /max
instead of /
- my attempts failed, I get 404 for http://localhost:3114/max/
and http://localhost:3114/max
.
(2) I wish to accept PUT
requests to /max
- how can I achieve this?
Please point me the right direction, thanks!
Edit 1
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
go http.HandleFunc("/ping", hello)
log.Fatal(http.ListenAndServe(":3114", nil))
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Println("STarting hello!")
log.Println("Got connection")
if r.URL.Path != "/ping" {
http.Error(w, "404 not found", http.StatusNotFound)
return
}
log.Println("Method:", r.Method)
switch r.Method {
case "GET":
send_this := "OK GOT ping! "
w.Write([]byte(send_this))
case "PUT":
fmt.Println("We got put!")
err := r.ParseForm()
checkErr(err)
fmt.Println("r now", r)
fmt.Println("r.Form", r.Form)
fmt.Println("r.PostForm", r.PostForm)
default:
send_this := "Please dont!"
w.Write([]byte(send_this))
fmt.Fprintf(w, "Unknown request!")
}
}
func checkErr(err error) {
if err != nil {
fmt.Println("Error", err)
}
}
I send a PUT request as curl -k http://localhost:3114/ping -T /tmp/a.go -v
, it shows:
STarting hello!
2019/06/07 15:05:10 Got connection
2019/06/07 15:05:10 Method: PUT
We got put!
r now &{PUT /ping HTTP/1.1 1 1 map[Content-Length:[10115] Expect:[100-continue] User-Agent:[curl/7.47.0] Accept:[*/*]] 0xc4200ec2e0 <nil> 10115 [] false localhost:3114 map[] map[] <nil> map[] 127.0.0.1:64612 /ping <nil> <nil> <nil> 0xc42005e340}
r.Form map[]
r.PostForm map[]
How can I find the actual data, and the filename that came in from PUT?
From https://golang.org/pkg/net/http/#ServeMux:
Patterns name fixed, rooted paths, like "/favicon.ico", or rooted subtrees, like "/images/" (note the trailing slash).
That means that /max
, which is a fixed rooted path, will match only /max
and the pattern /max/
, which is a rooted subtree, will match /max/
, any other path that starts with /max/
, and by default it will also match /max
.
http.Handle("/max/", http.FileServer(http.Dir(".")))
Depending on what the layout of your .
directory is, you may need to use https://golang.org/pkg/net/http/#StripPrefix.
Let's say your directory contains two files:
.
├── foo.txt
└── max
└── bar.txt
Given the handler above, a request to /max/bar.txt
will return the bar.txt
file, but a request to /max/foo.txt
or /foo.txt
will return 404
, no file.
So if you want to serve the files from the /max/
path, but your .
directory doesn't have a max
sub-directory then you can use StripPrefix
to remove the /max
prefix from the request's url path before it is passed on to the FileServer
.
http.Handle("/max/", http.StripPrefix("/max/", http.FileServer(http.Dir("."))))
To handle PUT
requests at the same route you need a custom handler.
type myhandler struct {
fs http.Handler
}
func (h myhandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != "PUT" {
// business as usual
h.fs.ServeHTTP(w, r)
return
}
// handle PUT
// ...
}
And then to register it, do:
fs := http.StripPrefix("/max/", http.FileServer(http.Dir(".")))
http.Handle("/max/", myhandler{fs: fs})