package httpsfv import ( "errors" "strings" "unicode" ) // ErrInvalidStringFormat is returned when a string format is invalid. var ErrInvalidStringFormat = errors.New("invalid string format") // marshalString serializes as defined in // https://httpwg.org/specs/rfc9651.html#ser-string. func marshalString(b *strings.Builder, s string) error { if err := b.WriteByte('"'); err != nil { return err } for i := 0; i < len(s); i++ { if s[i] <= '\u001F' || s[i] >= unicode.MaxASCII { return ErrInvalidStringFormat } switch s[i] { case '"', '\\': if err := b.WriteByte('\\'); err != nil { return err } } if err := b.WriteByte(s[i]); err != nil { return err } } if err := b.WriteByte('"'); err != nil { return err } return nil } // parseString parses as defined in // https://httpwg.org/specs/rfc9651.html#parse-string. func parseString(s *scanner) (string, error) { if s.eof() || s.data[s.off] != '"' { return "", &UnmarshalError{s.off, ErrInvalidStringFormat} } s.off++ var b strings.Builder for !s.eof() { c := s.data[s.off] s.off++ switch c { case '\\': if s.eof() { return "", &UnmarshalError{s.off, ErrInvalidStringFormat} } n := s.data[s.off] if n != '"' && n != '\\' { return "", &UnmarshalError{s.off, ErrInvalidStringFormat} } s.off++ if err := b.WriteByte(n); err != nil { return "", err } continue case '"': return b.String(), nil default: if c <= '\u001F' || c >= unicode.MaxASCII { return "", &UnmarshalError{s.off, ErrInvalidStringFormat} } if err := b.WriteByte(c); err != nil { return "", err } } } return "", &UnmarshalError{s.off, ErrInvalidStringFormat} }