From bf0d448e047b1b40a0b5c0db85e9c1e9ba420476 Mon Sep 17 00:00:00 2001 From: Ciprian Dorin Craciun Date: Mon, 12 Aug 2019 22:06:00 +0300 Subject: [PATCH] [sources] Move `Cache-Control` header into archive // Add support for custom `fasthttp` fork `AddRaw*` features --- sources/cmd/archiver.go | 11 ++++ sources/cmd/server.go | 116 +++++++++++++++++---------------- sources/lib/common/metadata.go | 13 ++-- 3 files changed, 78 insertions(+), 62 deletions(-) diff --git a/sources/cmd/archiver.go b/sources/cmd/archiver.go index bef587a..df92ef0 100644 --- a/sources/cmd/archiver.go +++ b/sources/cmd/archiver.go @@ -37,6 +37,7 @@ type context struct { compress string includeIndex bool includeStripped bool + includeCache bool includeEtag bool includeFileListing bool includeFolderListing bool @@ -410,9 +411,14 @@ func prepareDataContent (_context *context, _pathResolved string, _pathInArchive } _dataMeta := make (map[string]string, 16) + // _dataMeta["Content-Length"] = fmt.Sprintf ("%d", _dataSize) _dataMeta["Content-Type"] = _dataType _dataMeta["Content-Encoding"] = _dataEncoding + + if _context.includeCache { + _dataMeta["Cache-Control"] = "public, immutable, max-age=3600" + } if _context.includeEtag { _dataMeta["ETag"] = _fingerprintContent } @@ -631,6 +637,7 @@ func main_0 () (error) { var _compress string var _includeIndex bool var _includeStripped bool + var _includeCache bool var _includeEtag bool var _includeFileListing bool var _includeFolderListing bool @@ -662,6 +669,7 @@ func main_0 () (error) { --exclude-index --exclude-strip + --exclude-cache --exclude-etag --exclude-file-listing @@ -680,6 +688,7 @@ func main_0 () (error) { _compress_0 := _flags.String ("compress", "", "") _excludeIndex_0 := _flags.Bool ("exclude-index", false, "") _excludeStripped_0 := _flags.Bool ("exclude-strip", false, "") + _excludeCache_0 := _flags.Bool ("exclude-cache", false, "") _excludeEtag_0 := _flags.Bool ("exclude-etag", false, "") _excludeFileListing_0 := _flags.Bool ("exclude-file-listing", false, "") _includeFolderListing_0 := _flags.Bool ("include-folder-listing", false, "") @@ -692,6 +701,7 @@ func main_0 () (error) { _compress = *_compress_0 _includeIndex = ! *_excludeIndex_0 _includeStripped = ! *_excludeStripped_0 + _includeCache = ! *_excludeCache_0 _includeEtag = ! *_excludeEtag_0 _includeFileListing = ! *_excludeFileListing_0 _includeFolderListing = *_includeFolderListing_0 @@ -728,6 +738,7 @@ func main_0 () (error) { compress : _compress, includeIndex : _includeIndex, includeStripped : _includeStripped, + includeCache : _includeCache, includeEtag : _includeEtag, includeFileListing : _includeFileListing, includeFolderListing : _includeFolderListing, diff --git a/sources/cmd/server.go b/sources/cmd/server.go index 125bd22..1446cc8 100644 --- a/sources/cmd/server.go +++ b/sources/cmd/server.go @@ -105,19 +105,6 @@ func (_server *server) Serve (_context *fasthttp.RequestCtx) () { } } - if _server.securityHeadersEnabled { - if _server.securityHeadersTls { - _responseHeaders.AddRaw (StringToBytes ("Strict-Transport-Security"), StringToBytes ("max-age=31536000")) - _responseHeaders.AddRaw (StringToBytes ("Content-Security-Policy"), StringToBytes ("upgrade-insecure-requests")) - } - { - _responseHeaders.AddRaw (StringToBytes ("Referrer-Policy"), StringToBytes ("strict-origin-when-cross-origin")) - _responseHeaders.AddRaw (StringToBytes ("X-Content-Type-Options"), StringToBytes ("nosniff")) - _responseHeaders.AddRaw (StringToBytes ("X-XSS-Protection"), StringToBytes ("1; mode=block")) - _responseHeaders.AddRaw (StringToBytes ("X-Frame-Options"), StringToBytes ("sameorigin")) - } - } - var _fingerprints []byte var _namespaceAndPathSuffixes = [][2]string { @@ -226,8 +213,6 @@ func (_server *server) Serve (_context *fasthttp.RequestCtx) () { _fingerprintContent := _fingerprints[0:64] _fingerprintMeta := _fingerprints[65:129] - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("public, immutable, max-age=3600")) - var _data []byte if _server.cachedDataContent != nil { _data, _ = _server.cachedDataContent[BytesToString (_fingerprintContent)] @@ -271,31 +256,52 @@ func (_server *server) Serve (_context *fasthttp.RequestCtx) () { } _responseStatus := http.StatusOK - _handleHeader := func (_name []byte, _value []byte) { - if _name[0] != '_' { - _responseHeaders.AddRaw (_name, _value) - } else { - switch BytesToString (_name) { - case "_Status" : - if _value, _error := strconv.Atoi (BytesToString (_value)); _error == nil { - if (_value >= 200) && (_value <= 599) { - _responseStatus = _value - } else { - log.Printf ("[c2f7ec36] invalid data metadata for `%s`!\n", _requestHeaders.RequestURI ()) - _responseStatus = http.StatusInternalServerError - } - } else { - log.Printf ("[beedae55] invalid data metadata for `%s`!\n", _requestHeaders.RequestURI ()) - _responseStatus = http.StatusInternalServerError - } - default : - log.Printf ("[7acc7d90] invalid data metadata for `%s`!\n", _requestHeaders.RequestURI ()) - } - } + + _responseHeaders.AddRawLines (_dataMetaRaw) + +// FIXME: Re-enable this part! +// _handleHeader := func (_name []byte, _value []byte) { +// if _name[0] != '_' { +// _responseHeaders.AddRawKv (_name, _value) +// } else { +// switch BytesToString (_name) { +// case "!Status" : +// if _value, _error := strconv.Atoi (BytesToString (_value)); _error == nil { +// if (_value >= 200) && (_value <= 599) { +// _responseStatus = _value +// } else { +// log.Printf ("[c2f7ec36] invalid data metadata for `%s`!\n", _requestHeaders.RequestURI ()) +// _responseStatus = http.StatusInternalServerError +// } +// } else { +// log.Printf ("[beedae55] invalid data metadata for `%s`!\n", _requestHeaders.RequestURI ()) +// _responseStatus = http.StatusInternalServerError +// } +// default : +// log.Printf ("[7acc7d90] invalid data metadata for `%s`!\n", _requestHeaders.RequestURI ()) +// } +// } +// } +// if _error := MetadataDecodeIterate (_dataMetaRaw, _handleHeader); _error != nil { +// _server.ServeError (_context, http.StatusInternalServerError, _error, false) +// return +// } + + if _server.securityHeadersEnabled { + if _server.securityHeadersTls { + const _lines = ( + "Strict-Transport-Security: max-age=31536000" + "\r\n" + + "Content-Security-Policy: upgrade-insecure-requests" + "\r\n") + _responseHeaders.AddRawLines (StringToBytes (_lines)) + } + { + const _lines = ( + "Referrer-Policy: strict-origin-when-cross-origin" + "\r\n" + + "X-Content-Type-Options: nosniff" + "\r\n" + + "X-XSS-Protection: 1; mode=block" + "\r\n" + + "X-Frame-Options: sameorigin" + "\r\n") + _responseHeaders.AddRawLines (StringToBytes (_lines)) } - if _error := MetadataDecodeIterate (_dataMetaRaw, _handleHeader); _error != nil { - _server.ServeError (_context, http.StatusInternalServerError, _error, false) - return } if _server.debug { @@ -314,13 +320,13 @@ func (_server *server) ServeStatic (_context *fasthttp.RequestCtx, _status uint, _response := (*fasthttp.Response) (NoEscape (unsafe.Pointer (&_context.Response))) _responseHeaders := (*fasthttp.ResponseHeader) (NoEscape (unsafe.Pointer (&_context.Response.Header))) - _responseHeaders.AddRaw (StringToBytes ("Content-Type"), StringToBytes (_contentType)) - _responseHeaders.AddRaw (StringToBytes ("Content-Encoding"), StringToBytes (_contentEncoding)) + _responseHeaders.AddRawKv (StringToBytes ("Content-Type"), StringToBytes (_contentType)) + _responseHeaders.AddRawKv (StringToBytes ("Content-Encoding"), StringToBytes (_contentEncoding)) if _cache { - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("public, immutable, max-age=3600")) + _responseHeaders.AddRawLines (StringToBytes ("Cache-Control: public, immutable, max-age=3600\r\n")) } else { - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("no-cache")) + _responseHeaders.AddRawLines (StringToBytes ("Cache-Control: private, no-cache, no-store\r\n")) } _response.SetStatusCode (int (_status)) @@ -333,18 +339,14 @@ func (_server *server) ServeRedirect (_context *fasthttp.RequestCtx, _status uin _response := (*fasthttp.Response) (NoEscape (unsafe.Pointer (&_context.Response))) _responseHeaders := (*fasthttp.ResponseHeader) (NoEscape (unsafe.Pointer (&_context.Response.Header))) - _responseHeaders.AddRaw (StringToBytes ("Content-Encoding"), StringToBytes ("identity")) - _responseHeaders.AddRaw (StringToBytes ("Location"), _path) + _responseHeaders.SetCanonical (StringToBytes ("Location"), _path) if _cache { - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("public, immutable, max-age=3600")) + _responseHeaders.AddRawLines (StringToBytes ("Cache-Control: public, immutable, max-age=3600\r\n")) } else { - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("no-cache")) + _responseHeaders.AddRawLines (StringToBytes ("Cache-Control: private, no-cache, no-store\r\n")) } - _responseHeaders.AddRaw (StringToBytes ("Content-Type"), StringToBytes (MimeTypeText)) - _responseHeaders.AddRaw (StringToBytes ("Content-Encoding"), StringToBytes ("identity")) - _response.SetStatusCode (int (_status)) } @@ -354,14 +356,14 @@ func (_server *server) ServeError (_context *fasthttp.RequestCtx, _status uint, _response := (*fasthttp.Response) (NoEscape (unsafe.Pointer (&_context.Response))) _responseHeaders := (*fasthttp.ResponseHeader) (NoEscape (unsafe.Pointer (&_context.Response.Header))) - if _cache { - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("public, immutable, max-age=3600")) - } else { - _responseHeaders.AddRaw (StringToBytes ("Cache-Control"), StringToBytes ("no-cache")) - } + _responseHeaders.AddRawKv (StringToBytes ("Content-Type"), StringToBytes (ErrorBannerContentType)) + _responseHeaders.AddRawKv (StringToBytes ("Content-Encoding"), StringToBytes (ErrorBannerContentEncoding)) - _responseHeaders.AddRaw (StringToBytes ("Content-Type"), StringToBytes (ErrorBannerContentType)) - _responseHeaders.AddRaw (StringToBytes ("Content-Encoding"), StringToBytes (ErrorBannerContentEncoding)) + if _cache { + _responseHeaders.AddRawLines (StringToBytes ("Cache-Control: public, immutable, max-age=3600\r\n")) + } else { + _responseHeaders.AddRawLines (StringToBytes ("Cache-Control: private, no-cache, no-store\r\n")) + } if _banner, _bannerFound := ErrorBannersData[_status]; _bannerFound { _response.SetBodyRaw (_banner) diff --git a/sources/lib/common/metadata.go b/sources/lib/common/metadata.go index bdae360..3827d1d 100644 --- a/sources/lib/common/metadata.go +++ b/sources/lib/common/metadata.go @@ -37,9 +37,9 @@ func MetadataEncode (_metadata map[string]string) ([]byte, error) { return nil, fmt.Errorf ("[e8faf5bd] invalid metadata value: `%s`", _value) } _buffer.Write ([]byte (_key)) - _buffer.Write ([]byte (" : ")) + _buffer.Write ([]byte (": ")) _buffer.Write ([]byte (_value)) - _buffer.Write ([]byte ("\n")) + _buffer.Write ([]byte ("\r\n")) } _data := _buffer.Bytes () @@ -73,14 +73,17 @@ func MetadataDecodeIterate (_data []byte, _callback func ([]byte, []byte) ()) (e } _data := _data[_headerOffset :] - _headerLimit := bytes.IndexByte (_data, '\n') + _headerLimit := bytes.IndexByte (_data, '\r') if (_headerLimit == -1) { return fmt.Errorf ("[2d0d442a] invalid metadata encoding") } - _headerOffset += _headerLimit + 1 + if ((_headerOffset + _headerLimit) == (_dataSize - 1)) || (_data[_headerLimit + 1] != '\n') { + return fmt.Errorf ("[0e319685] invalid metadata encoding") + } + _headerOffset += _headerLimit + 2 _data = _data[: _headerLimit] - _separator := bytes.Index (_data, []byte (" : ")) + _separator := bytes.Index (_data, []byte (": ")) if _separator == -1 { return fmt.Errorf ("[41f3756c] invalid metadata encoding") }