aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-04-08 17:36:22 +0700
committerShulhan <ms@kilabit.info>2023-04-08 17:36:22 +0700
commit700b4bb063f0a75f19d4663b9ae705db5bda856a (patch)
treeb467ab186800599c02c5281f81b720a0239e6922 /lib
parent27662a36cd679529e98023206ff7a1826b78ac92 (diff)
downloadpakakeh.go-700b4bb063f0a75f19d4663b9ae705db5bda856a.tar.xz
lib/io: refactoring ParseContentType using lib/bytes#Parser
The libio.Reader will be deprecated and replaced with libbytes.Parser in the future.
Diffstat (limited to 'lib')
-rw-r--r--lib/email/contenttype.go61
-rw-r--r--lib/email/contenttype_test.go52
2 files changed, 63 insertions, 50 deletions
diff --git a/lib/email/contenttype.go b/lib/email/contenttype.go
index 951a993f..1fbe5a78 100644
--- a/lib/email/contenttype.go
+++ b/lib/email/contenttype.go
@@ -6,11 +6,10 @@ package email
import (
"bytes"
- "errors"
"fmt"
"strings"
- libio "github.com/shuLhan/share/lib/io"
+ libbytes "github.com/shuLhan/share/lib/bytes"
)
var (
@@ -41,63 +40,71 @@ func ParseContentType(raw []byte) (ct *ContentType, err error) {
return ct, nil
}
- r := &libio.Reader{}
- r.Init(raw)
- var c byte
+ var (
+ logp = `ParseContentType`
+ parser = libbytes.NewParser(raw, []byte{'/', ';'})
+ c byte
+ )
- ct.Top, _, c = r.ReadUntil([]byte{'/'}, nil)
- if c == 0 {
- return nil, errors.New("ParseContentType: missing subtype")
+ ct.Top, c = parser.Read()
+ if c != '/' {
+ return nil, fmt.Errorf(`%s: missing subtype`, logp)
}
if !isValidToken(ct.Top, false) {
- return nil, fmt.Errorf("ParseContentType: invalid type: '%s'", ct.Top)
+ return nil, fmt.Errorf(`%s: invalid type '%s'`, logp, ct.Top)
}
- ct.Sub, _, c = r.ReadUntil([]byte{';'}, nil)
+ ct.Sub, c = parser.Read()
if !isValidToken(ct.Sub, false) {
- return nil, fmt.Errorf("ParseContentType: invalid subtype: '%s'", ct.Sub)
+ return nil, fmt.Errorf(`%s: invalid subtype '%s'`, logp, ct.Sub)
}
if c == 0 {
return ct, nil
}
- c = r.SkipSpaces()
- ksep := []byte{'='}
- qsep := []byte{'"'}
- vsep := []byte{' '}
+ c = parser.SkipSpaces()
+ parser.SetDelimiters([]byte{'=', '"'})
for c != 0 {
param := Param{}
- param.Key, _, c = r.ReadUntil(ksep, nil)
+ param.Key, c = parser.ReadNoSpace()
if c == 0 {
// Ignore key without value
break
}
+ if c != '=' {
+ return nil, fmt.Errorf(`%s: expecting '=', got '%c'`, logp, c)
+ }
if !isValidToken(param.Key, false) {
- err = fmt.Errorf("ParseContentType: invalid parameter key: '%s'", param.Key)
- return nil, err
+ return nil, fmt.Errorf(`%s: invalid parameter key '%s'`, logp, param.Key)
}
- c = r.Current()
+ param.Value, c = parser.ReadNoSpace()
if c == '"' {
- r.SkipN(1)
- param.Value, _, c = r.ReadUntil(qsep, nil)
+ if len(param.Value) != 0 {
+ return nil, fmt.Errorf(`%s: invalid parameter value '%s'`, logp, param.Value)
+ }
+
+ // The param value may contain '=', remove it
+ // temporarily.
+ parser.RemoveDelimiters([]byte{'='})
+
+ param.Value, c = parser.ReadNoSpace()
if c != '"' {
- return nil, errors.New("ParseContentType: missing closing quote")
+ return nil, fmt.Errorf(`%s: missing closing quote`, logp)
}
param.Quoted = true
- } else {
- param.Value, _, _ = r.ReadUntil(vsep, nil)
+
+ parser.AddDelimiters([]byte{'='})
}
if !isValidToken(param.Value, param.Quoted) {
- err = fmt.Errorf("ParseContentType: invalid parameter value: '%s'", param.Value)
- return nil, err
+ return nil, fmt.Errorf(`%s: invalid parameter value '%s'`, logp, param.Value)
}
param.Key = bytes.ToLower(param.Key)
ct.Params = append(ct.Params, param)
- c = r.SkipSpaces()
+ c = parser.SkipSpaces()
}
return ct, nil
diff --git a/lib/email/contenttype_test.go b/lib/email/contenttype_test.go
index 2dd36a58..1b786631 100644
--- a/lib/email/contenttype_test.go
+++ b/lib/email/contenttype_test.go
@@ -12,47 +12,53 @@ import (
func TestParseContentType(t *testing.T) {
cases := []struct {
+ in string
expErr string
exp string
- in []byte
}{{
- exp: "text/plain; charset=us-ascii",
+ exp: `text/plain; charset=us-ascii`,
}, {
- in: []byte("text/;"),
- expErr: "ParseContentType: invalid subtype: ''",
+ in: `text/;`,
+ expErr: `ParseContentType: invalid subtype ''`,
}, {
- in: []byte("text/plain"),
- exp: "text/plain;",
+ in: `text/plain`,
+ exp: `text/plain;`,
}, {
- in: []byte("text ;"),
- expErr: "ParseContentType: missing subtype",
+ in: `text ;`,
+ expErr: `ParseContentType: missing subtype`,
}, {
- in: []byte("text /plain;"),
- expErr: "ParseContentType: invalid type: 'text '",
+ in: `text /plain;`,
+ expErr: `ParseContentType: invalid type 'text '`,
}, {
- in: []byte("text/ plain;"),
- expErr: "ParseContentType: invalid subtype: ' plain'",
+ in: `text/ plain;`,
+ expErr: `ParseContentType: invalid subtype ' plain'`,
}, {
- in: []byte("text/plain; key"),
- exp: "text/plain;",
+ in: `text/plain; key`,
+ exp: `text/plain;`,
}, {
- in: []byte("text/plain; ke(y)=value"),
- expErr: "ParseContentType: invalid parameter key: 'ke(y)'",
+ in: `text/plain; ke(y)=value`,
+ expErr: `ParseContentType: invalid parameter key 'ke(y)'`,
}, {
- in: []byte("text/plain; key=value?"),
- expErr: "ParseContentType: invalid parameter value: 'value?'",
+ in: `text/plain; key=value?`,
+ expErr: `ParseContentType: invalid parameter value 'value?'`,
}, {
- in: []byte(`text/plain; key="value?`),
- expErr: "ParseContentType: missing closing quote",
+ in: `text/plain; key"value"`,
+ expErr: `ParseContentType: expecting '=', got '"'`,
}, {
- in: []byte(`text/plain; key="value ?"`),
+ in: `text/plain; key=val "value"`,
+ expErr: `ParseContentType: invalid parameter value 'val'`,
+ }, {
+ in: `text/plain; key="value?`,
+ expErr: `ParseContentType: missing closing quote`,
+ }, {
+ in: `text/plain; key="value ?"`,
exp: `text/plain; key="value ?"`,
}}
for _, c := range cases {
- t.Logf("%s", c.in)
+ t.Log(c.in)
- got, err := ParseContentType(c.in)
+ got, err := ParseContentType([]byte(c.in))
if err != nil {
test.Assert(t, "error", c.expErr, err.Error())
continue