From beee05de3243654395b325c671b80c18de037c03 Mon Sep 17 00:00:00 2001 From: Ciprian Dorin Craciun Date: Tue, 13 Nov 2018 12:40:26 +0200 Subject: [PATCH] [server] Switch from `string` to `[]byte` and eliminate most heap allocations --- .x-run | 14 +++++ sources/cmd/server.go | 117 ++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/.x-run b/.x-run index 542e515..c25186b 100644 --- a/.x-run +++ b/.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 "${X_RUN[@]}" ':: examples / python-2.7.15-docs-html / archive / identity' "${X_RUN[@]}" ':: examples / python-2.7.15-docs-html / archive / gzip' diff --git a/sources/cmd/server.go b/sources/cmd/server.go index 4cd3db2..cc43cd6 100644 --- a/sources/cmd/server.go +++ b/sources/cmd/server.go @@ -5,12 +5,10 @@ package main import "bytes" import "flag" -import "fmt" import "io" import "io/ioutil" import "log" import "net/http" -import "net/url" import "os" import "time" @@ -38,8 +36,12 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () { _response := &_context.Response _responseHeaders := &_response.Header + _keyBuffer := [1024]byte {} + _pathNewBuffer := [1024]byte {} + _timestampBuffer := [128]byte {} + _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 ("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-XSS-Protection", "1; mode=block") - _responseHeaders.Set ("date", _timestampHttp) - _responseHeaders.Set ("last-modified", _timestampHttp) + _responseHeaders.SetBytesV ("date", _timestampHttp) + _responseHeaders.SetBytesV ("last-modified", _timestampHttp) _responseHeaders.Set ("age", "0") - _method := string (_requestHeaders.Method ()) - _path := string (_uri.Path ()) + _method := _requestHeaders.Method () + _path := _uri.Path () + _pathLen := len (_path) + _pathIsRoot := _pathLen == 1 + _pathHasSlash := !_pathIsRoot && (_path[_pathLen - 1] == '/') - if _method != http.MethodGet { - log.Printf ("[ww] [bce7a75b] invalid method `%s` for `%s`!", _method, _path) + if ! bytes.Equal ([]byte (http.MethodGet), _method) { + // log.Printf ("[ww] [bce7a75b] invalid method `%s` for `%s`!\n", _method, _path) _server.ServeError (_context, http.StatusMethodNotAllowed, nil) 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 - if (_path != "/") && (_path[len (_path) - 1] == '/') { - _path_0 = _path[: len (_path) - 1] + if _pathHasSlash { + _path_0 = _path[: _pathLen - 1] } _found : for _, _namespace := range []string {NamespaceFilesContent, NamespaceFoldersContent, NamespaceFoldersEntries} { - _key := fmt.Sprintf ("%s:%s", _namespace, _path_0) - if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil { + _key := _keyBuffer[:0] + _key = append (_key, _namespace ...) + _key = append (_key, ':') + _key = append (_key, _path_0 ...) + if _value, _error := _server.cdbReader.Get (_key); _error == nil { if _value != nil { - _fingerprint = string (_value) + _fingerprint = _value if (_namespace == NamespaceFoldersContent) || (_namespace == NamespaceFoldersEntries) { - if (_path == _path_0) && (_path != "/") { - _server.ServeRedirect (_context, http.StatusTemporaryRedirect, _path + "/") + if !_pathHasSlash { + _pathNew := _pathNewBuffer[:0] + _pathNew = append (_pathNew, _path_0 ...) + _pathNew = append (_pathNew, '/') + _server.ServeRedirect (_context, http.StatusTemporaryRedirect, _pathNew) return } } if _namespace == NamespaceFoldersEntries { - for _, _index := range []string { + for _, _indexName := range []string { "index.html", "index.htm", "index.xhtml", "index.xht", "index.txt", "index.json", "index.xml", } { - _pathIndex := _path_0 + "/" + _index - if _path_0 == "/" { - _pathIndex = "/" + _index + _key := _keyBuffer[:0] + _key = append (_key, NamespaceFilesContent ...) + _key = append (_key, '/') + if !_pathIsRoot { + _key = append (_key, _path_0 ...) } - _key := fmt.Sprintf ("%s:%s", NamespaceFilesContent, _pathIndex) - if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil { - _fingerprint = string (_value) + _key = append (_key, '/') + _key = append (_key, _indexName ...) + if _value, _error := _server.cdbReader.Get (_key); _error == nil { + _fingerprint = _value break _found } else { _server.ServeError (_context, http.StatusInternalServerError, _error) @@ -107,9 +126,10 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () { } } } - if _fingerprint == "" { - if _path != "/favicon.ico" { - log.Printf ("[ww] [7416f61d] not found for `%s`!", _path) + + if _fingerprint == nil { + if ! bytes.Equal ([]byte ("/favicon.ico"), _path) { + // log.Printf ("[ww] [7416f61d] not found `%s`!\n", _path) _server.ServeError (_context, http.StatusNotFound, nil) } else { _data, _dataContentType := FaviconData () @@ -125,12 +145,16 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () { var _data []byte { - _key := fmt.Sprintf ("%s:%s", NamespaceDataContent, _fingerprint) - if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil { + _key := _keyBuffer[:0] + _key = append (_key, NamespaceDataContent ...) + _key = append (_key, ':') + _key = append (_key, _fingerprint ...) + if _value, _error := _server.cdbReader.Get (_key); _error == nil { if _value != nil { _data = _value } 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 } } else { @@ -141,8 +165,11 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () { var _metadata [][2]string { - _key := fmt.Sprintf ("%s:%s", NamespaceDataMetadata, _fingerprint) - if _value, _error := _server.cdbReader.Get ([]byte (_key)); _error == nil { + _key := _keyBuffer[:0] + _key = append (_key, NamespaceDataMetadata ...) + _key = append (_key, ':') + _key = append (_key, _fingerprint ...) + if _value, _error := _server.cdbReader.Get (_key); _error == nil { if _value != nil { if _metadata_0, _error := MetadataDecode (_value); _error == nil { _metadata = _metadata_0 @@ -151,7 +178,8 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () { return } } 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 } } else { @@ -161,7 +189,7 @@ func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () { } 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 { @@ -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 _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-encoding", "identity") _responseHeaders.Set ("etag", "7aa652d8d607b85808c87c1c2105fbb5") _responseHeaders.Set ("cache-control", "public, immutable, max-age=3600") - _responseHeaders.Set ("location", _url) + _responseHeaders.SetBytesV ("location", _path) _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") _response.SetStatusCode (int (_status)) - _response.SetBody ([]byte (fmt.Sprintf ("[%d]", _status))) + // _response.SetBody ([]byte (fmt.Sprintf ("[%d]", _status))) LogError (_error, "") } @@ -263,6 +283,7 @@ func main_0 () (error) { } if _preload { + log.Printf ("[ii] [922ca187] preloading archive...\n") if _data, _error := ioutil.ReadAll (_file); _error == nil { _cdbFile = bytes.NewReader (_data) } else { @@ -286,9 +307,7 @@ func main_0 () (error) { debug : _debug, } - if _debug { - log.Printf ("[ii] [f11e4e37] listening on `http://%s/`", _bind) - } + log.Printf ("[ii] [f11e4e37] listening on `http://%s/`;\n", _bind) if _error := fasthttp.ListenAndServe (_bind, _server.HandleHTTP); _error != nil { AbortError (_error, "[44f45c67] failed starting server!")