mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-19 02:27:03 +00:00
Completed ParseEmailAddress()
This commit is contained in:
@@ -123,9 +123,11 @@ LOOP:
|
|||||||
inCharQuote = false
|
inCharQuote = false
|
||||||
case '0' <= c && c <= '9':
|
case '0' <= c && c <= '9':
|
||||||
// Numbers are OK
|
// Numbers are OK
|
||||||
|
buf.WriteByte(c)
|
||||||
inCharQuote = false
|
inCharQuote = false
|
||||||
case bytes.IndexByte([]byte("!#$%&'*+-/=?^_`{|}~"), c) >= 0:
|
case bytes.IndexByte([]byte("!#$%&'*+-/=?^_`{|}~"), c) >= 0:
|
||||||
// These specials can be used unquoted
|
// These specials can be used unquoted
|
||||||
|
buf.WriteByte(c)
|
||||||
inCharQuote = false
|
inCharQuote = false
|
||||||
case c == '.':
|
case c == '.':
|
||||||
// A single period is OK
|
// A single period is OK
|
||||||
@@ -133,10 +135,13 @@ LOOP:
|
|||||||
// Sequence of periods is not permitted
|
// Sequence of periods is not permitted
|
||||||
return "", "", fmt.Errorf("Sequence of periods is not permitted")
|
return "", "", fmt.Errorf("Sequence of periods is not permitted")
|
||||||
}
|
}
|
||||||
|
buf.WriteByte(c)
|
||||||
|
inCharQuote = false
|
||||||
case c == '\\':
|
case c == '\\':
|
||||||
inCharQuote = true
|
inCharQuote = true
|
||||||
case c == '"':
|
case c == '"':
|
||||||
if inCharQuote {
|
if inCharQuote {
|
||||||
|
buf.WriteByte(c)
|
||||||
inCharQuote = false
|
inCharQuote = false
|
||||||
} else if inStringQuote {
|
} else if inStringQuote {
|
||||||
inStringQuote = false
|
inStringQuote = false
|
||||||
@@ -149,6 +154,7 @@ LOOP:
|
|||||||
}
|
}
|
||||||
case c == '@':
|
case c == '@':
|
||||||
if inCharQuote || inStringQuote {
|
if inCharQuote || inStringQuote {
|
||||||
|
buf.WriteByte(c)
|
||||||
inCharQuote = false
|
inCharQuote = false
|
||||||
} else {
|
} else {
|
||||||
// End of local-part
|
// End of local-part
|
||||||
@@ -165,6 +171,7 @@ LOOP:
|
|||||||
return "", "", fmt.Errorf("Characters outside of US-ASCII range not permitted")
|
return "", "", fmt.Errorf("Characters outside of US-ASCII range not permitted")
|
||||||
default:
|
default:
|
||||||
if inCharQuote || inStringQuote {
|
if inCharQuote || inStringQuote {
|
||||||
|
buf.WriteByte(c)
|
||||||
inCharQuote = false
|
inCharQuote = false
|
||||||
} else {
|
} else {
|
||||||
return "", "", fmt.Errorf("Character %q must be quoted", c)
|
return "", "", fmt.Errorf("Character %q must be quoted", c)
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ func TestValidateLocal(t *testing.T) {
|
|||||||
{"user.", false, "Cannot end with a period"},
|
{"user.", false, "Cannot end with a period"},
|
||||||
{"james@mail", false, "Unquoted @ not permitted"},
|
{"james@mail", false, "Unquoted @ not permitted"},
|
||||||
{"first last", false, "Unquoted space not permitted"},
|
{"first last", false, "Unquoted space not permitted"},
|
||||||
|
{"tricky\\. ", false, "Unquoted space not permitted"},
|
||||||
{"no,commas", false, "Unquoted comma not allowed"},
|
{"no,commas", false, "Unquoted comma not allowed"},
|
||||||
{"t[es]t", false, "Unquoted square brackets not allowed"},
|
{"t[es]t", false, "Unquoted square brackets not allowed"},
|
||||||
{"james\\", false, "Cannot end with backslash quote"},
|
{"james\\", false, "Cannot end with backslash quote"},
|
||||||
@@ -110,10 +111,26 @@ func TestValidateLocal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseEmailAddress(t *testing.T) {
|
func TestParseEmailAddress(t *testing.T) {
|
||||||
|
// Test some good email addresses
|
||||||
var testTable = []struct {
|
var testTable = []struct {
|
||||||
input, local, domain string
|
input, local, domain string
|
||||||
}{
|
}{
|
||||||
{"root@localhost", "root", "localhost"},
|
{"root@localhost", "root", "localhost"},
|
||||||
|
{"FirstLast@domain.local", "FirstLast", "domain.local"},
|
||||||
|
{"route66@prodigy.net", "route66", "prodigy.net"},
|
||||||
|
{"lorbit!user@uucp", "lorbit!user", "uucp"},
|
||||||
|
{"user+spam@gmail.com", "user+spam", "gmail.com"},
|
||||||
|
{"first.last@domain.local", "first.last", "domain.local"},
|
||||||
|
{"first\\ last@_key.domain.com", "first last", "_key.domain.com"},
|
||||||
|
{"first\\\"last@a.b.c", "first\"last", "a.b.c"},
|
||||||
|
{"user\\@internal@myhost.ca", "user@internal", "myhost.ca"},
|
||||||
|
{"\"first last@evil\"@top-secret.gov", "first last@evil", "top-secret.gov"},
|
||||||
|
{"\"line\nfeed\"@linenoise.co.uk", "line\nfeed", "linenoise.co.uk"},
|
||||||
|
{"user+mailbox@host", "user+mailbox", "host"},
|
||||||
|
{"customer/department=shipping@host", "customer/department=shipping", "host"},
|
||||||
|
{"$A12345@host", "$A12345", "host"},
|
||||||
|
{"!def!xyz%abc@host", "!def!xyz%abc", "host"},
|
||||||
|
{"_somename@host", "_somename", "host"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range testTable {
|
for _, tt := range testTable {
|
||||||
@@ -131,4 +148,27 @@ func TestParseEmailAddress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that validations fail correctly
|
||||||
|
var badTable = []struct {
|
||||||
|
input, msg string
|
||||||
|
}{
|
||||||
|
{"", "Empty address not permitted"},
|
||||||
|
{"user", "Missing domain part"},
|
||||||
|
{"@host", "Missing local part"},
|
||||||
|
{"user\\@host", "Missing domain part"},
|
||||||
|
{"\"user@host\"", "Missing domain part"},
|
||||||
|
{"\"user@host", "Unterminated quoted string"},
|
||||||
|
{"first last@host", "Unquoted space"},
|
||||||
|
{"user@bad!domain", "Invalid domain"},
|
||||||
|
{".user@host", "Can't lead with a ."},
|
||||||
|
{"user.@host", "Can't end local with a dot"},
|
||||||
|
{"user@bad domain", "No spaces in domain permitted"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range badTable {
|
||||||
|
if _, _, err := ParseEmailAddress(tt.input); err == nil {
|
||||||
|
t.Errorf("Did not get expected error when parsing %q: %s", tt.input, tt.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user