"Fossies" - the Fresh Open Source Software Archive

Member "hugo-0.63.1/hugolib/alias.go" (23 Jan 2020, 4961 Bytes) of package /linux/www/hugo-0.63.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "alias.go": 0.62.2_vs_0.63.1.

    1 // Copyright 2019 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package hugolib
   15 
   16 import (
   17     "bytes"
   18     "errors"
   19     "fmt"
   20     "html/template"
   21     "io"
   22     "path"
   23     "path/filepath"
   24     "runtime"
   25     "strings"
   26 
   27     "github.com/gohugoio/hugo/common/loggers"
   28 
   29     "github.com/gohugoio/hugo/output"
   30     "github.com/gohugoio/hugo/publisher"
   31     "github.com/gohugoio/hugo/resources/page"
   32     "github.com/gohugoio/hugo/tpl"
   33 )
   34 
   35 var defaultAliasTemplates *template.Template
   36 
   37 type aliasHandler struct {
   38     t         tpl.TemplateHandler
   39     log       *loggers.Logger
   40     allowRoot bool
   41 }
   42 
   43 func newAliasHandler(t tpl.TemplateHandler, l *loggers.Logger, allowRoot bool) aliasHandler {
   44     return aliasHandler{t, l, allowRoot}
   45 }
   46 
   47 type aliasPage struct {
   48     Permalink string
   49     page.Page
   50 }
   51 
   52 func (a aliasHandler) renderAlias(permalink string, p page.Page) (io.Reader, error) {
   53 
   54     var templ tpl.Template
   55     var found bool
   56 
   57     templ, found = a.t.Lookup("alias.html")
   58     if !found {
   59         // TODO(bep) consolidate
   60         templ, found = a.t.Lookup("_internal/alias.html")
   61         if !found {
   62             return nil, errors.New("no alias template found")
   63         }
   64     }
   65 
   66     data := aliasPage{
   67         permalink,
   68         p,
   69     }
   70 
   71     buffer := new(bytes.Buffer)
   72     err := a.t.Execute(templ, buffer, data)
   73     if err != nil {
   74         return nil, err
   75     }
   76     return buffer, nil
   77 }
   78 
   79 func (s *Site) writeDestAlias(path, permalink string, outputFormat output.Format, p page.Page) (err error) {
   80     return s.publishDestAlias(false, path, permalink, outputFormat, p)
   81 }
   82 
   83 func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, outputFormat output.Format, p page.Page) (err error) {
   84     handler := newAliasHandler(s.Tmpl(), s.Log, allowRoot)
   85 
   86     s.Log.DEBUG.Println("creating alias:", path, "redirecting to", permalink)
   87 
   88     targetPath, err := handler.targetPathAlias(path)
   89     if err != nil {
   90         return err
   91     }
   92 
   93     aliasContent, err := handler.renderAlias(permalink, p)
   94     if err != nil {
   95         return err
   96     }
   97 
   98     pd := publisher.Descriptor{
   99         Src:          aliasContent,
  100         TargetPath:   targetPath,
  101         StatCounter:  &s.PathSpec.ProcessingStats.Aliases,
  102         OutputFormat: outputFormat,
  103     }
  104 
  105     return s.publisher.Publish(pd)
  106 
  107 }
  108 
  109 func (a aliasHandler) targetPathAlias(src string) (string, error) {
  110     originalAlias := src
  111     if len(src) <= 0 {
  112         return "", fmt.Errorf("alias \"\" is an empty string")
  113     }
  114 
  115     alias := path.Clean(filepath.ToSlash(src))
  116 
  117     if !a.allowRoot && alias == "/" {
  118         return "", fmt.Errorf("alias \"%s\" resolves to website root directory", originalAlias)
  119     }
  120 
  121     components := strings.Split(alias, "/")
  122 
  123     // Validate against directory traversal
  124     if components[0] == ".." {
  125         return "", fmt.Errorf("alias \"%s\" traverses outside the website root directory", originalAlias)
  126     }
  127 
  128     // Handle Windows file and directory naming restrictions
  129     // See "Naming Files, Paths, and Namespaces" on MSDN
  130     // https://msdn.microsoft.com/en-us/library/aa365247%28v=VS.85%29.aspx?f=255&MSPPError=-2147217396
  131     msgs := []string{}
  132     reservedNames := []string{"CON", "PRN", "AUX", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}
  133 
  134     if strings.ContainsAny(alias, ":*?\"<>|") {
  135         msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains invalid characters on Windows: : * ? \" < > |", originalAlias))
  136     }
  137     for _, ch := range alias {
  138         if ch < ' ' {
  139             msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains ASCII control code (0x00 to 0x1F), invalid on Windows: : * ? \" < > |", originalAlias))
  140             continue
  141         }
  142     }
  143     for _, comp := range components {
  144         if strings.HasSuffix(comp, " ") || strings.HasSuffix(comp, ".") {
  145             msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains component with a trailing space or period, problematic on Windows", originalAlias))
  146         }
  147         for _, r := range reservedNames {
  148             if comp == r {
  149                 msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains component with reserved name \"%s\" on Windows", originalAlias, r))
  150             }
  151         }
  152     }
  153     if len(msgs) > 0 {
  154         if runtime.GOOS == "windows" {
  155             for _, m := range msgs {
  156                 a.log.ERROR.Println(m)
  157             }
  158             return "", fmt.Errorf("cannot create \"%s\": Windows filename restriction", originalAlias)
  159         }
  160         for _, m := range msgs {
  161             a.log.INFO.Println(m)
  162         }
  163     }
  164 
  165     // Add the final touch
  166     alias = strings.TrimPrefix(alias, "/")
  167     if strings.HasSuffix(alias, "/") {
  168         alias = alias + "index.html"
  169     } else if !strings.HasSuffix(alias, ".html") {
  170         alias = alias + "/" + "index.html"
  171     }
  172 
  173     return filepath.FromSlash(alias), nil
  174 }