[server] Switch from string
to []byte
and eliminate most heap allocations
This commit is contained in:
parent
dff1321a35
commit
beee05de32
2 changed files with 82 additions and 49 deletions
14
.x-run
14
.x-run
|
@ -264,6 +264,20 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<< examples / fontawesome / serve
|
||||||
|
exec -- "${X_RUN[@]}" ':: go / execute / server / release' \
|
||||||
|
--archive ./.databases/fontawesome.cdb \
|
||||||
|
--bind 127.198.53.69:8080 \
|
||||||
|
--preload \
|
||||||
|
--debug \
|
||||||
|
"${@}" \
|
||||||
|
#
|
||||||
|
exit -- 1
|
||||||
|
!!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<< examples / python-2.7.15-docs-html / archive / all
|
<< examples / python-2.7.15-docs-html / archive / all
|
||||||
"${X_RUN[@]}" ':: examples / python-2.7.15-docs-html / archive / identity'
|
"${X_RUN[@]}" ':: examples / python-2.7.15-docs-html / archive / identity'
|
||||||
"${X_RUN[@]}" ':: examples / python-2.7.15-docs-html / archive / gzip'
|
"${X_RUN[@]}" ':: examples / python-2.7.15-docs-html / archive / gzip'
|
||||||
|
|
|
@ -5,12 +5,10 @@ package main
|
||||||
|
|
||||||
import "bytes"
|
import "bytes"
|
||||||
import "flag"
|
import "flag"
|
||||||
import "fmt"
|
|
||||||
import "io"
|
import "io"
|
||||||
import "io/ioutil"
|
import "io/ioutil"
|
||||||
import "log"
|
import "log"
|
||||||
import "net/http"
|
import "net/http"
|
||||||
import "net/url"
|
|
||||||
import "os"
|
import "os"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
@ -38,8 +36,12 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
_response := &_context.Response
|
_response := &_context.Response
|
||||||
_responseHeaders := &_response.Header
|
_responseHeaders := &_response.Header
|
||||||
|
|
||||||
|
_keyBuffer := [1024]byte {}
|
||||||
|
_pathNewBuffer := [1024]byte {}
|
||||||
|
_timestampBuffer := [128]byte {}
|
||||||
|
|
||||||
_timestamp := time.Now ()
|
_timestamp := time.Now ()
|
||||||
_timestampHttp := _timestamp.Format (http.TimeFormat)
|
_timestampHttp := _timestamp.AppendFormat (_timestampBuffer[:0], http.TimeFormat)
|
||||||
|
|
||||||
// _responseHeaders.Set ("Content-Security-Policy", "upgrade-insecure-requests")
|
// _responseHeaders.Set ("Content-Security-Policy", "upgrade-insecure-requests")
|
||||||
_responseHeaders.Set ("Referrer-Policy", "strict-origin-when-cross-origin")
|
_responseHeaders.Set ("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||||
|
@ -47,51 +49,68 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
_responseHeaders.Set ("X-content-type-Options", "nosniff")
|
_responseHeaders.Set ("X-content-type-Options", "nosniff")
|
||||||
_responseHeaders.Set ("X-XSS-Protection", "1; mode=block")
|
_responseHeaders.Set ("X-XSS-Protection", "1; mode=block")
|
||||||
|
|
||||||
_responseHeaders.Set ("date", _timestampHttp)
|
_responseHeaders.SetBytesV ("date", _timestampHttp)
|
||||||
_responseHeaders.Set ("last-modified", _timestampHttp)
|
_responseHeaders.SetBytesV ("last-modified", _timestampHttp)
|
||||||
_responseHeaders.Set ("age", "0")
|
_responseHeaders.Set ("age", "0")
|
||||||
|
|
||||||
_method := string (_requestHeaders.Method ())
|
_method := _requestHeaders.Method ()
|
||||||
_path := string (_uri.Path ())
|
_path := _uri.Path ()
|
||||||
|
_pathLen := len (_path)
|
||||||
|
_pathIsRoot := _pathLen == 1
|
||||||
|
_pathHasSlash := !_pathIsRoot && (_path[_pathLen - 1] == '/')
|
||||||
|
|
||||||
if _method != http.MethodGet {
|
if ! bytes.Equal ([]byte (http.MethodGet), _method) {
|
||||||
log.Printf ("[ww] [bce7a75b] invalid method `%s` for `%s`!", _method, _path)
|
// log.Printf ("[ww] [bce7a75b] invalid method `%s` for `%s`!\n", _method, _path)
|
||||||
_server.ServeError (_context, http.StatusMethodNotAllowed, nil)
|
_server.ServeError (_context, http.StatusMethodNotAllowed, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (_pathLen == 0) || (_path[0] != '/') {
|
||||||
|
// log.Printf ("[ww] [fa6b1923] invalid path `%s`!\n", _path)
|
||||||
|
_server.ServeError (_context, http.StatusBadRequest, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var _fingerprint string
|
var _fingerprint []byte
|
||||||
{
|
{
|
||||||
_path_0 := _path
|
_path_0 := _path
|
||||||
if (_path != "/") && (_path[len (_path) - 1] == '/') {
|
if _pathHasSlash {
|
||||||
_path_0 = _path[: len (_path) - 1]
|
_path_0 = _path[: _pathLen - 1]
|
||||||
}
|
}
|
||||||
_found : for _, _namespace := range []string {NamespaceFilesContent, NamespaceFoldersContent, NamespaceFoldersEntries} {
|
_found : for _, _namespace := range []string {NamespaceFilesContent, NamespaceFoldersContent, NamespaceFoldersEntries} {
|
||||||
_key := fmt.Sprintf ("%s:%s", _namespace, _path_0)
|
_key := _keyBuffer[:0]
|
||||||
if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil {
|
_key = append (_key, _namespace ...)
|
||||||
|
_key = append (_key, ':')
|
||||||
|
_key = append (_key, _path_0 ...)
|
||||||
|
if _value, _error := _server.cdbReader.Get (_key); _error == nil {
|
||||||
if _value != nil {
|
if _value != nil {
|
||||||
_fingerprint = string (_value)
|
_fingerprint = _value
|
||||||
if (_namespace == NamespaceFoldersContent) || (_namespace == NamespaceFoldersEntries) {
|
if (_namespace == NamespaceFoldersContent) || (_namespace == NamespaceFoldersEntries) {
|
||||||
if (_path == _path_0) && (_path != "/") {
|
if !_pathHasSlash {
|
||||||
_server.ServeRedirect (_context, http.StatusTemporaryRedirect, _path + "/")
|
_pathNew := _pathNewBuffer[:0]
|
||||||
|
_pathNew = append (_pathNew, _path_0 ...)
|
||||||
|
_pathNew = append (_pathNew, '/')
|
||||||
|
_server.ServeRedirect (_context, http.StatusTemporaryRedirect, _pathNew)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _namespace == NamespaceFoldersEntries {
|
if _namespace == NamespaceFoldersEntries {
|
||||||
for _, _index := range []string {
|
for _, _indexName := range []string {
|
||||||
"index.html", "index.htm",
|
"index.html", "index.htm",
|
||||||
"index.xhtml", "index.xht",
|
"index.xhtml", "index.xht",
|
||||||
"index.txt",
|
"index.txt",
|
||||||
"index.json",
|
"index.json",
|
||||||
"index.xml",
|
"index.xml",
|
||||||
} {
|
} {
|
||||||
_pathIndex := _path_0 + "/" + _index
|
_key := _keyBuffer[:0]
|
||||||
if _path_0 == "/" {
|
_key = append (_key, NamespaceFilesContent ...)
|
||||||
_pathIndex = "/" + _index
|
_key = append (_key, '/')
|
||||||
|
if !_pathIsRoot {
|
||||||
|
_key = append (_key, _path_0 ...)
|
||||||
}
|
}
|
||||||
_key := fmt.Sprintf ("%s:%s", NamespaceFilesContent, _pathIndex)
|
_key = append (_key, '/')
|
||||||
if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil {
|
_key = append (_key, _indexName ...)
|
||||||
_fingerprint = string (_value)
|
if _value, _error := _server.cdbReader.Get (_key); _error == nil {
|
||||||
|
_fingerprint = _value
|
||||||
break _found
|
break _found
|
||||||
} else {
|
} else {
|
||||||
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
||||||
|
@ -107,9 +126,10 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _fingerprint == "" {
|
|
||||||
if _path != "/favicon.ico" {
|
if _fingerprint == nil {
|
||||||
log.Printf ("[ww] [7416f61d] not found for `%s`!", _path)
|
if ! bytes.Equal ([]byte ("/favicon.ico"), _path) {
|
||||||
|
// log.Printf ("[ww] [7416f61d] not found `%s`!\n", _path)
|
||||||
_server.ServeError (_context, http.StatusNotFound, nil)
|
_server.ServeError (_context, http.StatusNotFound, nil)
|
||||||
} else {
|
} else {
|
||||||
_data, _dataContentType := FaviconData ()
|
_data, _dataContentType := FaviconData ()
|
||||||
|
@ -125,12 +145,16 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
|
|
||||||
var _data []byte
|
var _data []byte
|
||||||
{
|
{
|
||||||
_key := fmt.Sprintf ("%s:%s", NamespaceDataContent, _fingerprint)
|
_key := _keyBuffer[:0]
|
||||||
if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil {
|
_key = append (_key, NamespaceDataContent ...)
|
||||||
|
_key = append (_key, ':')
|
||||||
|
_key = append (_key, _fingerprint ...)
|
||||||
|
if _value, _error := _server.cdbReader.Get (_key); _error == nil {
|
||||||
if _value != nil {
|
if _value != nil {
|
||||||
_data = _value
|
_data = _value
|
||||||
} else {
|
} else {
|
||||||
_server.ServeError (_context, http.StatusInternalServerError, fmt.Errorf ("[0165c193] missing data content: `%s`", _fingerprint))
|
// log.Printf ("[ee] [0165c193] missing data content for `%s`!\n", _fingerprint)
|
||||||
|
_server.ServeError (_context, http.StatusInternalServerError, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,8 +165,11 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
|
|
||||||
var _metadata [][2]string
|
var _metadata [][2]string
|
||||||
{
|
{
|
||||||
_key := fmt.Sprintf ("%s:%s", NamespaceDataMetadata, _fingerprint)
|
_key := _keyBuffer[:0]
|
||||||
if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil {
|
_key = append (_key, NamespaceDataMetadata ...)
|
||||||
|
_key = append (_key, ':')
|
||||||
|
_key = append (_key, _fingerprint ...)
|
||||||
|
if _value, _error := _server.cdbReader.Get (_key); _error == nil {
|
||||||
if _value != nil {
|
if _value != nil {
|
||||||
if _metadata_0, _error := MetadataDecode (_value); _error == nil {
|
if _metadata_0, _error := MetadataDecode (_value); _error == nil {
|
||||||
_metadata = _metadata_0
|
_metadata = _metadata_0
|
||||||
|
@ -151,7 +178,8 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_server.ServeError (_context, http.StatusInternalServerError, fmt.Errorf ("[e8702411] missing data metadata: `%s`", _fingerprint))
|
// log.Printf ("[ee] [e8702411] missing data metadata for `%s`!\n", _fingerprint)
|
||||||
|
_server.ServeError (_context, http.StatusInternalServerError, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,7 +189,7 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _server.debug {
|
if _server.debug {
|
||||||
log.Printf ("[dd] [b15f3cad] serving for `%s`...\n", _path)
|
// log.Printf ("[dd] [b15f3cad] serving for `%s`...\n", _path)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, _metadata := range _metadata {
|
for _, _metadata := range _metadata {
|
||||||
|
@ -176,26 +204,18 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (_server *server) ServeRedirect (_context *fasthttp.RequestCtx, _status uint, _urlRaw string) () {
|
func (_server *server) ServeRedirect (_context *fasthttp.RequestCtx, _status uint, _path []byte) () {
|
||||||
_response := &_context.Response
|
_response := &_context.Response
|
||||||
_responseHeaders := &_response.Header
|
_responseHeaders := &_response.Header
|
||||||
|
|
||||||
var _url string
|
|
||||||
if _url_0, _error := url.Parse (_urlRaw); _error == nil {
|
|
||||||
_url = _url_0.String ()
|
|
||||||
} else {
|
|
||||||
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_responseHeaders.Set ("content-type", MimeTypeText)
|
_responseHeaders.Set ("content-type", MimeTypeText)
|
||||||
_responseHeaders.Set ("content-encoding", "identity")
|
_responseHeaders.Set ("content-encoding", "identity")
|
||||||
_responseHeaders.Set ("etag", "7aa652d8d607b85808c87c1c2105fbb5")
|
_responseHeaders.Set ("etag", "7aa652d8d607b85808c87c1c2105fbb5")
|
||||||
_responseHeaders.Set ("cache-control", "public, immutable, max-age=3600")
|
_responseHeaders.Set ("cache-control", "public, immutable, max-age=3600")
|
||||||
_responseHeaders.Set ("location", _url)
|
_responseHeaders.SetBytesV ("location", _path)
|
||||||
|
|
||||||
_response.SetStatusCode (int (_status))
|
_response.SetStatusCode (int (_status))
|
||||||
_response.SetBody ([]byte (fmt.Sprintf ("[%d] %s", _status, _url)))
|
// _response.SetBody ([]byte (fmt.Sprintf ("[%d] %s", _status, _path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -208,7 +228,7 @@ func (_server *server) ServeError (_context *fasthttp.RequestCtx, _status uint,
|
||||||
_responseHeaders.Set ("cache-control", "no-cache")
|
_responseHeaders.Set ("cache-control", "no-cache")
|
||||||
|
|
||||||
_response.SetStatusCode (int (_status))
|
_response.SetStatusCode (int (_status))
|
||||||
_response.SetBody ([]byte (fmt.Sprintf ("[%d]", _status)))
|
// _response.SetBody ([]byte (fmt.Sprintf ("[%d]", _status)))
|
||||||
|
|
||||||
LogError (_error, "")
|
LogError (_error, "")
|
||||||
}
|
}
|
||||||
|
@ -263,6 +283,7 @@ func main_0 () (error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _preload {
|
if _preload {
|
||||||
|
log.Printf ("[ii] [922ca187] preloading archive...\n")
|
||||||
if _data, _error := ioutil.ReadAll (_file); _error == nil {
|
if _data, _error := ioutil.ReadAll (_file); _error == nil {
|
||||||
_cdbFile = bytes.NewReader (_data)
|
_cdbFile = bytes.NewReader (_data)
|
||||||
} else {
|
} else {
|
||||||
|
@ -286,9 +307,7 @@ func main_0 () (error) {
|
||||||
debug : _debug,
|
debug : _debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _debug {
|
log.Printf ("[ii] [f11e4e37] listening on `http://%s/`;\n", _bind)
|
||||||
log.Printf ("[ii] [f11e4e37] listening on `http://%s/`", _bind)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _error := fasthttp.ListenAndServe (_bind, _server.HandleHTTP); _error != nil {
|
if _error := fasthttp.ListenAndServe (_bind, _server.HandleHTTP); _error != nil {
|
||||||
AbortError (_error, "[44f45c67] failed starting server!")
|
AbortError (_error, "[44f45c67] failed starting server!")
|
||||||
|
|
Loading…
Reference in a new issue