repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / pgs
Eric Bower · 25 Feb 24

header.go

  1package pgs
  2
  3import (
  4	"fmt"
  5	"slices"
  6	"strings"
  7)
  8
  9type HeaderRule struct {
 10	Path    string
 11	Headers []*HeaderLine
 12}
 13
 14type HeaderLine struct {
 15	Path  string
 16	Name  string
 17	Value string
 18}
 19
 20var headerDenyList = []string{
 21	"accept-ranges",
 22	"age",
 23	"allow",
 24	"alt-svc",
 25	"connection",
 26	"content-encoding",
 27	"content-length",
 28	"content-range",
 29	"date",
 30	"location",
 31	"server",
 32	"trailer",
 33	"transfer-encoding",
 34	"upgrade",
 35}
 36
 37// from https://github.com/netlify/build/tree/main/packages/headers-parser
 38func parseHeaderText(text string) ([]*HeaderRule, error) {
 39	rules := []*HeaderRule{}
 40	parsed := []*HeaderLine{}
 41	lines := strings.Split(text, "\n")
 42	for _, line := range lines {
 43		parsedLine, err := parseLine(strings.TrimSpace(line))
 44		if parsedLine == nil {
 45			continue
 46		}
 47		if err != nil {
 48			return rules, err
 49		}
 50		parsed = append(parsed, parsedLine)
 51	}
 52
 53	var prevPath *HeaderRule
 54	for _, rule := range parsed {
 55		if rule.Path != "" {
 56			if prevPath != nil {
 57				if len(prevPath.Headers) > 0 {
 58					rules = append(rules, prevPath)
 59				}
 60			}
 61
 62			prevPath = &HeaderRule{
 63				Path: rule.Path,
 64			}
 65		} else if prevPath != nil {
 66			// do not add headers in deny list
 67			if slices.Contains(headerDenyList, rule.Name) {
 68				continue
 69			}
 70			prevPath.Headers = append(
 71				prevPath.Headers,
 72				&HeaderLine{Name: rule.Name, Value: rule.Value},
 73			)
 74		}
 75	}
 76
 77	// cleanup
 78	if prevPath != nil && len(prevPath.Headers) > 0 {
 79		rules = append(rules, prevPath)
 80	}
 81
 82	return rules, nil
 83}
 84
 85func parseLine(line string) (*HeaderLine, error) {
 86	rule := &HeaderLine{}
 87
 88	if isPathLine(line) {
 89		rule.Path = line
 90		return rule, nil
 91	}
 92
 93	if isEmpty(line) {
 94		return nil, nil
 95	}
 96
 97	if isComment(line) {
 98		return nil, nil
 99	}
100
101	if !strings.Contains(line, ":") {
102		return nil, nil
103	}
104
105	results := strings.SplitN(line, ":", 2)
106	name := strings.ToLower(strings.TrimSpace(results[0]))
107	value := strings.TrimSpace(results[1])
108
109	if name == "" {
110		return nil, fmt.Errorf("header name cannot be empty")
111	}
112
113	if value == "" {
114		return nil, fmt.Errorf("header value cannot be empty")
115	}
116
117	rule.Name = name
118	rule.Value = value
119	return rule, nil
120}
121
122func isComment(line string) bool {
123	return strings.HasPrefix(line, "#")
124}
125
126func isEmpty(line string) bool {
127	return line == ""
128}
129
130func isPathLine(line string) bool {
131	return strings.HasPrefix(line, "/")
132}