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}