File: headers.go

package info (click to toggle)
golang-codeberg-git-pages-go-headers 1.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 52 kB
  • sloc: makefile: 2
file content (91 lines) | stat: -rw-r--r-- 2,087 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package headers

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
	"strings"
)

// Rule contains headers for a single path.
type Rule struct {
	Path    string
	Headers http.Header
}

// Parse parses the given reader.
func Parse(r io.Reader) (rules []Rule, err error) {
	scanner := bufio.NewScanner(r)
	current := Rule{}
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" || strings.HasPrefix(strings.TrimLeft(line, " \t"), "#") {
			continue
		}
		if line[0] != ' ' && line[0] != '\t' {
			// this is a path line
			if current.Headers != nil {
				rules = append(rules, current)
			}
			current = Rule{Path: strings.TrimRight(line, " \t"), Headers: http.Header{}}
		} else {
			// this is a header line
			if current.Path == "" {
				return nil, fmt.Errorf("header line without preceding path line: %q", line)
			}
			name, value, found := strings.Cut(line, ":")
			if !found {
				return nil, fmt.Errorf("header line without separator: %q", line)
			}
			current.Headers.Add(strings.TrimSpace(name), strings.TrimSpace(value))
		}
	}
	if current.Headers != nil {
		rules = append(rules, current)
	}
	err = scanner.Err()
	return
}

// ParseString parses the given string.
func ParseString(str string) ([]Rule, error) {
	return Parse(strings.NewReader(str))
}

// Unparse serializes to the given writer.
func Unparse(w io.Writer, rules []Rule) (err error) {
	for _, rule := range rules {
		if strings.IndexAny(rule.Path, " \t\n") == 0 {
			return fmt.Errorf("invalid path: %v", rule.Path)
		}
		_, err = fmt.Fprintf(w, "%s\n", rule.Path)
		if err != nil {
			return
		}
		for name, values := range rule.Headers {
			for _, value := range values {
				_, err = fmt.Fprintf(w, "\t%s: %s\n", name, value)
				if err != nil {
					return
				}
			}
		}
	}
	return
}

// UnparseString serializes to a string.
func UnparseString(rules []Rule) (result string, err error) {
	builder := strings.Builder{}
	err = Unparse(&builder, rules)
	return builder.String(), err
}

// Panics if there is an error.
func Must[T any](value T, err error) T {
	if err != nil {
		panic(err)
	}
	return value
}