mirror of
https://code.rocketnine.space/tslocum/twins.git
synced 2024-11-27 13:28:15 +01:00
Support custom content types
This commit is contained in:
parent
3cb855acfa
commit
cac10df2f6
4 changed files with 51 additions and 19 deletions
|
@ -18,6 +18,11 @@ Address to listen for connections on in the format of `interface:port`.
|
||||||
|
|
||||||
`:1965`
|
`:1965`
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
Content types may be defined by file extension. When a type is not defined for
|
||||||
|
the requested file extension, content type is detected automatically.
|
||||||
|
|
||||||
## Hosts
|
## Hosts
|
||||||
|
|
||||||
Hosts are defined by their hostname followed by one or more paths to serve.
|
Hosts are defined by their hostname followed by one or more paths to serve.
|
||||||
|
@ -181,6 +186,10 @@ References:
|
||||||
# Address to listen on
|
# Address to listen on
|
||||||
listen: :1965
|
listen: :1965
|
||||||
|
|
||||||
|
# Custom content types
|
||||||
|
types:
|
||||||
|
.json: application/json; charset=UTF-8
|
||||||
|
|
||||||
# Hosts and paths to serve
|
# Hosts and paths to serve
|
||||||
hosts:
|
hosts:
|
||||||
default: # Default host configuration
|
default: # Default host configuration
|
||||||
|
|
20
config.go
20
config.go
|
@ -68,6 +68,8 @@ type hostConfig struct {
|
||||||
type serverConfig struct {
|
type serverConfig struct {
|
||||||
Listen string
|
Listen string
|
||||||
|
|
||||||
|
Types map[string]string
|
||||||
|
|
||||||
Hosts map[string]*hostConfig
|
Hosts map[string]*hostConfig
|
||||||
|
|
||||||
DisableSize bool
|
DisableSize bool
|
||||||
|
@ -108,6 +110,10 @@ func readconfig(configPath string) error {
|
||||||
log.Fatal("listen address must be specified")
|
log.Fatal("listen address must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Types == nil {
|
||||||
|
config.Types = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
if config.SaneEOL {
|
if config.SaneEOL {
|
||||||
newLine = "\n"
|
newLine = "\n"
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,6 +132,20 @@ func readconfig(configPath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default content types
|
||||||
|
if config.Types[".htm"] == "" {
|
||||||
|
config.Types[".htm"] = htmlType
|
||||||
|
}
|
||||||
|
if config.Types[".html"] == "" {
|
||||||
|
config.Types[".html"] = htmlType
|
||||||
|
}
|
||||||
|
if config.Types[".gmi"] == "" {
|
||||||
|
config.Types[".gmi"] = geminiType
|
||||||
|
}
|
||||||
|
if config.Types[".gemini"] == "" {
|
||||||
|
config.Types[".gemini"] = geminiType
|
||||||
|
}
|
||||||
|
|
||||||
defaultHost := config.Hosts["default"]
|
defaultHost := config.Hosts["default"]
|
||||||
delete(config.Hosts, "default")
|
delete(config.Hosts, "default")
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/h2non/filetype"
|
"github.com/h2non/filetype"
|
||||||
)
|
)
|
||||||
|
@ -98,33 +97,35 @@ func serveFile(c net.Conn, serve *pathConfig, filePath string) {
|
||||||
file, _ := os.Open(filePath)
|
file, _ := os.Open(filePath)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
// Read file header
|
// Read content type
|
||||||
buf := make([]byte, 261)
|
var (
|
||||||
n, _ := file.Read(buf)
|
buf = make([]byte, 261)
|
||||||
|
n int
|
||||||
// Write response header
|
)
|
||||||
var contentType string
|
contentType := config.Types[filepath.Ext(filePath)]
|
||||||
if strings.HasSuffix(filePath, ".html") && strings.HasSuffix(filePath, ".htm") {
|
|
||||||
contentType = "text/html; charset=utf-8"
|
|
||||||
} else if strings.HasSuffix(filePath, ".txt") && strings.HasSuffix(filePath, ".text") {
|
|
||||||
contentType = "text/plain; charset=utf-8"
|
|
||||||
} else if !strings.HasSuffix(filePath, ".gmi") && !strings.HasSuffix(filePath, ".gemini") {
|
|
||||||
kind, _ := filetype.Match(buf[:n])
|
|
||||||
if kind != filetype.Unknown {
|
|
||||||
contentType = kind.MIME.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if contentType == "" {
|
if contentType == "" {
|
||||||
contentType = geminiType
|
n, _ = file.Read(buf)
|
||||||
|
kind, err := filetype.Match(buf[:n])
|
||||||
|
if err == nil && kind != filetype.Unknown && kind.MIME.Value != "" {
|
||||||
|
contentType = kind.MIME.Value
|
||||||
|
} else {
|
||||||
|
contentType = plainType
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file size
|
||||||
size := int64(-1)
|
size := int64(-1)
|
||||||
info, err := file.Stat()
|
info, err := file.Stat()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
size = info.Size()
|
size = info.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write response header
|
||||||
writeSuccess(c, serve, contentType, size)
|
writeSuccess(c, serve, contentType, size)
|
||||||
|
|
||||||
// Write body
|
// Write file contents
|
||||||
|
if n > 0 {
|
||||||
c.Write(buf[:n])
|
c.Write(buf[:n])
|
||||||
|
}
|
||||||
io.Copy(c, file)
|
io.Copy(c, file)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ const (
|
||||||
|
|
||||||
urlMaxLength = 1024
|
urlMaxLength = 1024
|
||||||
|
|
||||||
|
plainType = "text/plain; charset=utf-8"
|
||||||
geminiType = "text/gemini; charset=utf-8"
|
geminiType = "text/gemini; charset=utf-8"
|
||||||
|
htmlType = "text/html; charset=utf-8"
|
||||||
|
|
||||||
logTimeFormat = "2006-01-02 15:04:05"
|
logTimeFormat = "2006-01-02 15:04:05"
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue