"Fossies" - the Fresh Open Source Software Archive

Member "gdrive-2.1.1/vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates.go" (28 May 2021, 5224 Bytes) of package /linux/misc/gdrive-2.1.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.

    1 // Copyright 2013 Joshua Tacoma. All rights reserved.
    2 // Use of this source code is governed by a BSD-style
    3 // license that can be found in the LICENSE file.
    4 
    5 // Package uritemplates is a level 3 implementation of RFC 6570 (URI
    6 // Template, http://tools.ietf.org/html/rfc6570).
    7 // uritemplates does not support composite values (in Go: slices or maps)
    8 // and so does not qualify as a level 4 implementation.
    9 package uritemplates
   10 
   11 import (
   12     "bytes"
   13     "errors"
   14     "regexp"
   15     "strconv"
   16     "strings"
   17 )
   18 
   19 var (
   20     unreserved = regexp.MustCompile("[^A-Za-z0-9\\-._~]")
   21     reserved   = regexp.MustCompile("[^A-Za-z0-9\\-._~:/?#[\\]@!$&'()*+,;=]")
   22     validname  = regexp.MustCompile("^([A-Za-z0-9_\\.]|%[0-9A-Fa-f][0-9A-Fa-f])+$")
   23     hex        = []byte("0123456789ABCDEF")
   24 )
   25 
   26 func pctEncode(src []byte) []byte {
   27     dst := make([]byte, len(src)*3)
   28     for i, b := range src {
   29         buf := dst[i*3 : i*3+3]
   30         buf[0] = 0x25
   31         buf[1] = hex[b/16]
   32         buf[2] = hex[b%16]
   33     }
   34     return dst
   35 }
   36 
   37 func escape(s string, allowReserved bool) string {
   38     if allowReserved {
   39         return string(reserved.ReplaceAllFunc([]byte(s), pctEncode))
   40     }
   41     return string(unreserved.ReplaceAllFunc([]byte(s), pctEncode))
   42 }
   43 
   44 // A uriTemplate is a parsed representation of a URI template.
   45 type uriTemplate struct {
   46     raw   string
   47     parts []templatePart
   48 }
   49 
   50 // parse parses a URI template string into a uriTemplate object.
   51 func parse(rawTemplate string) (*uriTemplate, error) {
   52     split := strings.Split(rawTemplate, "{")
   53     parts := make([]templatePart, len(split)*2-1)
   54     for i, s := range split {
   55         if i == 0 {
   56             if strings.Contains(s, "}") {
   57                 return nil, errors.New("unexpected }")
   58             }
   59             parts[i].raw = s
   60             continue
   61         }
   62         subsplit := strings.Split(s, "}")
   63         if len(subsplit) != 2 {
   64             return nil, errors.New("malformed template")
   65         }
   66         expression := subsplit[0]
   67         var err error
   68         parts[i*2-1], err = parseExpression(expression)
   69         if err != nil {
   70             return nil, err
   71         }
   72         parts[i*2].raw = subsplit[1]
   73     }
   74     return &uriTemplate{
   75         raw:   rawTemplate,
   76         parts: parts,
   77     }, nil
   78 }
   79 
   80 type templatePart struct {
   81     raw           string
   82     terms         []templateTerm
   83     first         string
   84     sep           string
   85     named         bool
   86     ifemp         string
   87     allowReserved bool
   88 }
   89 
   90 type templateTerm struct {
   91     name     string
   92     explode  bool
   93     truncate int
   94 }
   95 
   96 func parseExpression(expression string) (result templatePart, err error) {
   97     switch expression[0] {
   98     case '+':
   99         result.sep = ","
  100         result.allowReserved = true
  101         expression = expression[1:]
  102     case '.':
  103         result.first = "."
  104         result.sep = "."
  105         expression = expression[1:]
  106     case '/':
  107         result.first = "/"
  108         result.sep = "/"
  109         expression = expression[1:]
  110     case ';':
  111         result.first = ";"
  112         result.sep = ";"
  113         result.named = true
  114         expression = expression[1:]
  115     case '?':
  116         result.first = "?"
  117         result.sep = "&"
  118         result.named = true
  119         result.ifemp = "="
  120         expression = expression[1:]
  121     case '&':
  122         result.first = "&"
  123         result.sep = "&"
  124         result.named = true
  125         result.ifemp = "="
  126         expression = expression[1:]
  127     case '#':
  128         result.first = "#"
  129         result.sep = ","
  130         result.allowReserved = true
  131         expression = expression[1:]
  132     default:
  133         result.sep = ","
  134     }
  135     rawterms := strings.Split(expression, ",")
  136     result.terms = make([]templateTerm, len(rawterms))
  137     for i, raw := range rawterms {
  138         result.terms[i], err = parseTerm(raw)
  139         if err != nil {
  140             break
  141         }
  142     }
  143     return result, err
  144 }
  145 
  146 func parseTerm(term string) (result templateTerm, err error) {
  147     // TODO(djd): Remove "*" suffix parsing once we check that no APIs have
  148     // mistakenly used that attribute.
  149     if strings.HasSuffix(term, "*") {
  150         result.explode = true
  151         term = term[:len(term)-1]
  152     }
  153     split := strings.Split(term, ":")
  154     if len(split) == 1 {
  155         result.name = term
  156     } else if len(split) == 2 {
  157         result.name = split[0]
  158         var parsed int64
  159         parsed, err = strconv.ParseInt(split[1], 10, 0)
  160         result.truncate = int(parsed)
  161     } else {
  162         err = errors.New("multiple colons in same term")
  163     }
  164     if !validname.MatchString(result.name) {
  165         err = errors.New("not a valid name: " + result.name)
  166     }
  167     if result.explode && result.truncate > 0 {
  168         err = errors.New("both explode and prefix modifers on same term")
  169     }
  170     return result, err
  171 }
  172 
  173 // Expand expands a URI template with a set of values to produce a string.
  174 func (t *uriTemplate) Expand(values map[string]string) string {
  175     var buf bytes.Buffer
  176     for _, p := range t.parts {
  177         p.expand(&buf, values)
  178     }
  179     return buf.String()
  180 }
  181 
  182 func (tp *templatePart) expand(buf *bytes.Buffer, values map[string]string) {
  183     if len(tp.raw) > 0 {
  184         buf.WriteString(tp.raw)
  185         return
  186     }
  187     var first = true
  188     for _, term := range tp.terms {
  189         value, exists := values[term.name]
  190         if !exists {
  191             continue
  192         }
  193         if first {
  194             buf.WriteString(tp.first)
  195             first = false
  196         } else {
  197             buf.WriteString(tp.sep)
  198         }
  199         tp.expandString(buf, term, value)
  200     }
  201 }
  202 
  203 func (tp *templatePart) expandName(buf *bytes.Buffer, name string, empty bool) {
  204     if tp.named {
  205         buf.WriteString(name)
  206         if empty {
  207             buf.WriteString(tp.ifemp)
  208         } else {
  209             buf.WriteString("=")
  210         }
  211     }
  212 }
  213 
  214 func (tp *templatePart) expandString(buf *bytes.Buffer, t templateTerm, s string) {
  215     if len(s) > t.truncate && t.truncate > 0 {
  216         s = s[:t.truncate]
  217     }
  218     tp.expandName(buf, t.name, len(s) == 0)
  219     buf.WriteString(escape(s, tp.allowReserved))
  220 }