[archiver] Add initial support for redirects file.

This commit is contained in:
Ciprian Dorin Craciun 2022-08-26 12:27:59 +03:00
parent 16efc8f8fc
commit d55dbe84e8

View file

@ -13,6 +13,7 @@ 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 "path/filepath" import "path/filepath"
import "runtime" import "runtime"
@ -335,6 +336,44 @@ func archiveReferenceAndData (_context *context, _namespace string, _pathResolve
} }
func archiveReferenceAndDataWithMeta (_context *context, _namespace string, _pathInArchive string, _dataContent []byte, _dataMeta map[string]string) (string, string, error) {
var _fingerprintContent string
var _fingerprintMeta string
var _dataMetaRaw []byte
_fingerprintContentRaw := blake3.Sum256 (_dataContent)
_fingerprintContent = hex.EncodeToString (_fingerprintContentRaw[:])
if _wasStored, _ := _context.storedDataContent[_fingerprintContent]; _wasStored {
_dataContent = nil
}
if _fingerprintMeta_0, _dataMetaRaw_0, _error := prepareDataMeta (_context, _dataMeta); _error != nil {
return "", "", _error
} else {
_fingerprintMeta = _fingerprintMeta_0
_dataMetaRaw = _dataMetaRaw_0
}
if _error := archiveReference (_context, _namespace, _pathInArchive, _fingerprintContent, _fingerprintMeta); _error != nil {
return "", "", _error
}
if _dataMetaRaw != nil {
if _error := archiveDataMeta (_context, _fingerprintMeta, _dataMetaRaw); _error != nil {
return "", "", _error
}
}
if _dataContent != nil {
if _error := archiveDataContent (_context, _fingerprintContent, _dataContent); _error != nil {
return "", "", _error
}
}
return _fingerprintContent, _fingerprintMeta, nil
}
func archiveDataContent (_context *context, _fingerprintContent string, _dataContent []byte) (error) { func archiveDataContent (_context *context, _fingerprintContent string, _dataContent []byte) (error) {
@ -926,6 +965,8 @@ func walkPath (_context *context, _pathResolved string, _pathInArchive string, _
var _wildcardName string var _wildcardName string
var _wildcardStatus uint var _wildcardStatus uint
var _redirectsName string
if _context.debug { if _context.debug {
log.Printf ("[dd] [2d22d910] folder |> `%s`\n", _pathInArchive) log.Printf ("[dd] [2d22d910] folder |> `%s`\n", _pathInArchive)
} }
@ -969,6 +1010,13 @@ func walkPath (_context *context, _pathResolved string, _pathInArchive string, _
_wildcardStatus = 404 _wildcardStatus = 404
continue continue
} }
if (_childName == "_redirects") || (_childName == "_redirects.txt") {
if _redirectsName != "" {
return nil, fmt.Errorf ("[fbc0ee12] duplicate redirects files found: `%s` and `%s`!", _childName, _redirectsName)
}
_redirectsName = _childName
continue
}
if ShouldSkipName (_childName) { if ShouldSkipName (_childName) {
if _context.debug { if _context.debug {
log.Printf ("[dd] [f11b5ba1] skip !! `%s`\n", _childPathInArchive) log.Printf ("[dd] [f11b5ba1] skip !! `%s`\n", _childPathInArchive)
@ -1008,6 +1056,16 @@ func walkPath (_context *context, _pathResolved string, _pathInArchive string, _
return nil, _error return nil, _error
} }
} }
if _redirectsName != "" {
_childPathInArchive := _pathInArchive
_childPathResolved := _childsPathResolved[_redirectsName]
if _context.debug {
log.Printf ("[dd] [f49aa9f5] redirects -- `%s` -> `%s`\n", _childPathInArchive, _childPathResolved)
}
if _error := walkRedirects (_context, _childPathResolved, _childPathInArchive); _error != nil {
return nil, _error
}
}
if _context.debug { if _context.debug {
log.Printf ("[dd] [ce1fe181] folder |> `%s`\n", _pathInArchive) log.Printf ("[dd] [ce1fe181] folder |> `%s`\n", _pathInArchive)
@ -1048,6 +1106,144 @@ func walkPath (_context *context, _pathResolved string, _pathInArchive string, _
func walkRedirects (_context *context, _pathResolved string, _pathInArchive string) (error) {
_redirectsData, _error := os.ReadFile (_pathResolved)
if _error != nil {
return _error
}
_redirectLines := strings.Split (string (_redirectsData), "\n")
for _, _redirectLine := range _redirectLines {
_redirectLine = strings.ReplaceAll (_redirectLine, "\t", " ")
_redirectLine = strings.Trim (_redirectLine, " ")
for {
_redirectLine_0 := strings.ReplaceAll (_redirectLine, " ", " ")
if _redirectLine == _redirectLine_0 {
break
}
_redirectLine = _redirectLine_0
}
if _redirectLine == "" {
continue
}
if _redirectLine[0] == '#' {
continue
}
_redirectParts := strings.Split (_redirectLine, " ")
if len (_redirectParts) != 3 {
return fmt.Errorf ("[bf358c0a] invalid redirect statement: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_source := _redirectParts[0]
_target := _redirectParts[1]
_code := 0
switch _redirectParts[2] {
case "301" : _code = 301
case "302" : _code = 302
case "303" : _code = 303
case "307" : _code = 307
case "308" : _code = 308
default :
return fmt.Errorf ("[fb9ac5a5] invalid redirect code: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_sourceParsed := false
if ! _sourceParsed {
for _, _schemePrefix := range []string { "://", "http://", "https://" } {
if strings.HasPrefix (_source, _schemePrefix) {
if _pathInArchive != "/" {
return fmt.Errorf ("[ceac537a] invalid redirect absolute source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_source_0 := "http://" + strings.TrimPrefix (_source, _schemePrefix)
_sourceUrl, _error := url.ParseRequestURI (_source_0)
if _error != nil {
return fmt.Errorf ("[dd43230e] invalid redirect source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_sourceCanonical := _sourceUrl.String ()
if _sourceCanonical != _source_0 {
return fmt.Errorf ("[2c6dc950] invalid redirect source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_source = strings.TrimPrefix (_source, _schemePrefix)
_source = "://" + _source
_sourceParsed = true
break
}
}
}
if ! _sourceParsed {
if _source[0] == '.' {
if _pathInArchive == "/" {
_source = "/" + _source[2:]
} else {
_source = _pathInArchive + "/" + _source[2:]
}
} else if _source[0] == '/' {
if _pathInArchive != "/" {
return fmt.Errorf ("[99e025fe] invalid redirect absolute source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
} else {
return fmt.Errorf ("[2e716cd2] invalid redirect source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_sourceUrl, _error := url.ParseRequestURI (_source)
if _error != nil {
return fmt.Errorf ("[be9abd4d] invalid redirect source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_sourceCanonical := _sourceUrl.String ()
if _sourceCanonical != _source {
return fmt.Errorf ("[3c31deb4] invalid redirect source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_sourceParsed = true
}
if ! _sourceParsed {
return fmt.Errorf ("[8305376f] invalid redirect source: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
{
_targetUrl, _error := url.Parse (_target)
if _error != nil {
return fmt.Errorf ("[968f7208] invalid redirect target: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
_targetCanonical := _targetUrl.String ()
if _targetCanonical != _target {
return fmt.Errorf ("[c22eea24] invalid redirect target: `%s` -- `%s`!", _pathResolved, _redirectLine)
}
}
if _context.debug {
log.Printf ("[dd] [c8139953] redirect -- `%s` -> `%s` (%d)\n", _source, _target, _code)
}
_dataMeta := map[string]string {
"!Status" : fmt.Sprintf ("%d", _code),
"Location" : _target,
}
_fingerprintContentRaw := blake3.Sum256 ([]byte (_redirectLine))
_fingerprintContent := hex.EncodeToString (_fingerprintContentRaw[:])
if _context.includeCache {
_dataMeta["Cache-Control"] = "public, immutable, max-age=3600"
}
if _context.includeEtag {
_dataMeta["ETag"] = _fingerprintContent
}
if _, _, _error := archiveReferenceAndDataWithMeta (_context, NamespaceFilesContent, _source, []byte (""), _dataMeta); _error != nil {
return _error
}
}
return nil
}
func Main () () { func Main () () {
if len (os.Args) == 2 { if len (os.Args) == 2 {