-func getLine(data []byte) (line, rest []byte) {
- i := bytes.Index(data, []byte{'\n'})
- j := i + 1
- if i < 0 {
- i = len(data)
- j = i
- } else if i > 0 && data[i-1] == '\r' {
- i--
+func ParseFields(s []byte) (fields map[string]string, rest []byte, err error) {
+ rest = s
+ fields = make(map[string]string)
+ key := ""
+ // \n is optional after the last field and an extra \n is allowed as well
+ for len(rest) > 0 {
+ var line []byte
+ line, rest = getLine(rest)
+ // empty line after the last field is consumed
+ if len(line) == 0 {
+ break
+ }
+ if line[0] == ' ' && key != "" {
+ // "Key: v1\n v2\n" is equivalent to "Key: v1 v2\n"
+ fields[key] += string(line)
+ continue
+ }
+ if line[0] < 'A' || line[0] > 'Z' {
+ err = fmt.Errorf("ParseFields: field name must start with an upper-case ascii letter")
+ return
+ }
+ i := bytes.IndexByte(line, ':')
+ if i < 0 {
+ err = fmt.Errorf("ParseFields: missing ':'")
+ return
+ }
+ key = string(line[:i])
+ if _, ok := fields[key]; ok {
+ err = fmt.Errorf("ParseFields: repeated fields are not allowed")
+ return
+ }
+ fields[key] = string(line[i+1:])
+ }
+ for key, v := range fields {
+ // either a single space follows ':' or the value is empty
+ // good: "Key:\n", "Key:\n value\n", "Key: value\n", "Key: v1\n v2\n"
+ // bad: "Key:value\n", "Key: \nvalue\n"
+ // bad but not checked here: "Key: \n", "Key: value \n", "Key:\n \n value\n"
+ if len(v) == 0 {
+ continue
+ }
+ if v[0] != ' ' {
+ err = fmt.Errorf("ParseFields: ':' is not followed by ' '")
+ return
+ }
+ fields[key] = v[1:]