I am just starting out with Go and am trying to learn how to build a simple web app without using 3rd party libraries / packages.
Using this post and this code as a guideline, I've hacked the following together:
package main
import (
"bytes"
"net/http"
"os"
"path"
"time"
)
type StaticFS map[string]*staticFile
type staticFile struct {
name string
data []byte
fs StaticFS
}
func LoadAsset(name string, data string, fs StaticFS) *staticFile {
return &staticFile{name: name,
data: []byte(data),
fs: fs}
}
func (fs StaticFS) prepare(name string) (*staticFile, error) {
f, present := fs[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
return f, nil
}
func (fs StaticFS) Open(name string) (http.File, error) {
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}
func (f *staticFile) File() (http.File, error) {
type httpFile struct {
*bytes.Reader
*staticFile
}
return &httpFile{
Reader: bytes.NewReader(f.data),
staticFile: f,
}, nil
}
//implement the rest of os.FileInfo
func (f *staticFile) Close() error {
return nil
}
func (f *staticFile) Stat() (os.FileInfo, error) {
return f, nil
}
func (f *staticFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
func (f *staticFile) Name() string {
return f.name
}
func (f *staticFile) Size() int64 {
return int64(len(f.data))
}
func (f *staticFile) Mode() os.FileMode {
return 0
}
func (f *staticFile) ModTime() time.Time {
return time.Time{}
}
func (f *staticFile) IsDir() bool {
return false
}
func (f *staticFile) Sys() interface{} {
return f
}
func main() {
const HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<p>Hello World</p>
</main>
</body>
</html>
`
const CSS = `
p {
color:red;
text-align:center;
}
`
ASSETS := make(StaticFS)
ASSETS["index.html"] = LoadAsset("index.html", HTML, ASSETS)
ASSETS["style.css"] = LoadAsset("style.css", CSS, ASSETS)
http.Handle("/", http.FileServer(ASSETS))
http.ListenAndServe(":8080", nil)
}
Which compiles fine, but doesn't actually produce any results other than 404 page not found..
What I want to achieve is having a package in my app that allows me to make a map, embed some static content such as css and js in it and then serve it with http.Handle - Without using 3rd party tools like go-bindata, rice or anything else.
Any help would be greatly appreciated..
Here is the main code we will need to look at, which comes from the source regarding
http.FileServer:In the
ServeHTTPmethod, you will see a call to an unexported function.where
upathis the request's URL path that is guaranteed to begin with "/".In
serveFile,fs.Open(name)is called, wherefsis theFileSystemyou provided andnameis the argument we passed aspath.Clean(upath). Note thatpath.Cleanis already being called, so you should not need to call this in yourpreparemethod.The takeaway here is that you are storing your "file names" without a preceding "/", which would represent they are in the root of the filesystem.
You can fix this two different ways.
1.
2.