net: vfmt everything
parent
535dcac8fa
commit
d7d9305d96
|
@ -44,7 +44,6 @@ const (
|
||||||
]
|
]
|
||||||
vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [
|
vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [
|
||||||
'vlib/strconv/' /* prevent conflicts, till the new pure V string interpolation is merged */,
|
'vlib/strconv/' /* prevent conflicts, till the new pure V string interpolation is merged */,
|
||||||
'vlib/net/http/' /* prevent conflicts, till ipv6 support is merged */,
|
|
||||||
'vlib/term/ui/input.v' /* comment after a struct embed is removed */,
|
'vlib/term/ui/input.v' /* comment after a struct embed is removed */,
|
||||||
'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */,
|
'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */,
|
||||||
'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */,
|
'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */,
|
||||||
|
|
|
@ -100,13 +100,13 @@ const aoffset = __offsetof(Addr, addr)
|
||||||
fn (a Addr) len() u32 {
|
fn (a Addr) len() u32 {
|
||||||
match a.family() {
|
match a.family() {
|
||||||
.ip {
|
.ip {
|
||||||
return sizeof(Ip) + aoffset
|
return sizeof(Ip) + net.aoffset
|
||||||
}
|
}
|
||||||
.ip6 {
|
.ip6 {
|
||||||
return sizeof(Ip6) + aoffset
|
return sizeof(Ip6) + net.aoffset
|
||||||
}
|
}
|
||||||
.unix {
|
.unix {
|
||||||
return sizeof(Unix) + aoffset
|
return sizeof(Unix) + net.aoffset
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
panic('Unknown address family')
|
panic('Unknown address family')
|
||||||
|
|
|
@ -14,7 +14,7 @@ $if windows {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_diagnostics() {
|
fn test_diagnostics() {
|
||||||
dump(net.aoffset)
|
dump(aoffset)
|
||||||
eprintln('--------')
|
eprintln('--------')
|
||||||
in6 := C.sockaddr_in6{}
|
in6 := C.sockaddr_in6{}
|
||||||
our_ip6 := Ip6{}
|
our_ip6 := Ip6{}
|
||||||
|
@ -72,17 +72,17 @@ fn test_sizes_unix_sun_path() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_offsets_ipv6() {
|
fn test_offsets_ipv6() {
|
||||||
assert __offsetof(C.sockaddr_in6, sin6_addr) == __offsetof(Ip6, addr) + net.aoffset
|
assert __offsetof(C.sockaddr_in6, sin6_addr) == __offsetof(Ip6, addr) + aoffset
|
||||||
assert __offsetof(C.sockaddr_in6, sin6_port) == __offsetof(Ip6, port) + net.aoffset
|
assert __offsetof(C.sockaddr_in6, sin6_port) == __offsetof(Ip6, port) + aoffset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_offsets_ipv4() {
|
fn test_offsets_ipv4() {
|
||||||
assert __offsetof(C.sockaddr_in, sin_addr) == __offsetof(Ip, addr) + net.aoffset
|
assert __offsetof(C.sockaddr_in, sin_addr) == __offsetof(Ip, addr) + aoffset
|
||||||
assert __offsetof(C.sockaddr_in, sin_port) == __offsetof(Ip, port) + net.aoffset
|
assert __offsetof(C.sockaddr_in, sin_port) == __offsetof(Ip, port) + aoffset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_offsets_unix() {
|
fn test_offsets_unix() {
|
||||||
assert __offsetof(C.sockaddr_un, sun_path) == __offsetof(Unix, path) + net.aoffset
|
assert __offsetof(C.sockaddr_un, sun_path) == __offsetof(Unix, path) + aoffset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_sizes_ipv6() {
|
fn test_sizes_ipv6() {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import strings
|
||||||
// followed by \r\n as a line separator,
|
// followed by \r\n as a line separator,
|
||||||
// followed by a chunk of data of the given size.
|
// followed by a chunk of data of the given size.
|
||||||
// The end is marked with a chunk with size 0.
|
// The end is marked with a chunk with size 0.
|
||||||
|
|
||||||
struct ChunkScanner {
|
struct ChunkScanner {
|
||||||
mut:
|
mut:
|
||||||
pos int
|
pos int
|
||||||
|
@ -23,7 +24,7 @@ fn (mut s ChunkScanner) read_chunk_size() int {
|
||||||
if !c.is_hex_digit() {
|
if !c.is_hex_digit() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n = n<<4
|
n = n << 4
|
||||||
n += int(unhex(c))
|
n += int(unhex(c))
|
||||||
s.pos++
|
s.pos++
|
||||||
}
|
}
|
||||||
|
@ -33,11 +34,9 @@ fn (mut s ChunkScanner) read_chunk_size() int {
|
||||||
fn unhex(c byte) byte {
|
fn unhex(c byte) byte {
|
||||||
if `0` <= c && c <= `9` {
|
if `0` <= c && c <= `9` {
|
||||||
return c - `0`
|
return c - `0`
|
||||||
}
|
} else if `a` <= c && c <= `f` {
|
||||||
else if `a` <= c && c <= `f` {
|
|
||||||
return c - `a` + 10
|
return c - `a` + 10
|
||||||
}
|
} else if `A` <= c && c <= `F` {
|
||||||
else if `A` <= c && c <= `F` {
|
|
||||||
return c - `A` + 10
|
return c - `A` + 10
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -10,20 +10,21 @@ pub struct Cookie {
|
||||||
pub mut:
|
pub mut:
|
||||||
name string
|
name string
|
||||||
value string
|
value string
|
||||||
path string // optional
|
path string // optional
|
||||||
domain string // optional
|
domain string // optional
|
||||||
expires time.Time // optional
|
expires time.Time // optional
|
||||||
raw_expires string // for reading cookies only. optional.
|
raw_expires string // for reading cookies only. optional.
|
||||||
// max_age=0 means no 'Max-Age' attribute specified.
|
// max_age=0 means no 'Max-Age' attribute specified.
|
||||||
// max_age<0 means delete cookie now, equivalently 'Max-Age: 0'
|
// max_age<0 means delete cookie now, equivalently 'Max-Age: 0'
|
||||||
// max_age>0 means Max-Age attribute present and given in seconds
|
// max_age>0 means Max-Age attribute present and given in seconds
|
||||||
max_age int
|
max_age int
|
||||||
secure bool
|
secure bool
|
||||||
http_only bool
|
http_only bool
|
||||||
same_site SameSite
|
same_site SameSite
|
||||||
raw string
|
raw string
|
||||||
unparsed []string // Raw text of unparsed attribute-value pairs
|
unparsed []string // Raw text of unparsed attribute-value pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
// SameSite allows a server to define a cookie attribute making it impossible for
|
// SameSite allows a server to define a cookie attribute making it impossible for
|
||||||
// the browser to send this cookie along with cross-site requests. The main
|
// the browser to send this cookie along with cross-site requests. The main
|
||||||
// goal is to mitigate the risk of cross-origin information leakage, and provide
|
// goal is to mitigate the risk of cross-origin information leakage, and provide
|
||||||
|
@ -61,12 +62,10 @@ pub fn read_set_cookies(h map[string][]string) []&Cookie {
|
||||||
if !is_cookie_name_valid(name) {
|
if !is_cookie_name_valid(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value := parse_cookie_value(raw_value, true) or {
|
value := parse_cookie_value(raw_value, true) or { continue }
|
||||||
continue
|
mut c := &Cookie{
|
||||||
}
|
name: name
|
||||||
mut c := &Cookie{
|
value: value
|
||||||
name: name,
|
|
||||||
value: value,
|
|
||||||
raw: line
|
raw: line
|
||||||
}
|
}
|
||||||
for i, _ in parts {
|
for i, _ in parts {
|
||||||
|
@ -182,10 +181,11 @@ pub fn read_cookies(h map[string][]string, filter string) []&Cookie {
|
||||||
if filter != '' && filter != name {
|
if filter != '' && filter != name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = parse_cookie_value(val, true) or {
|
val = parse_cookie_value(val, true) or { continue }
|
||||||
continue
|
cookies << &Cookie{
|
||||||
|
name: name
|
||||||
|
value: val
|
||||||
}
|
}
|
||||||
cookies << &Cookie{name: name, value: val}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cookies
|
return cookies
|
||||||
|
@ -203,7 +203,8 @@ pub fn (c &Cookie) str() string {
|
||||||
// extra_cookie_length derived from typical length of cookie attributes
|
// extra_cookie_length derived from typical length of cookie attributes
|
||||||
// see RFC 6265 Sec 4.1.
|
// see RFC 6265 Sec 4.1.
|
||||||
extra_cookie_length := 110
|
extra_cookie_length := 110
|
||||||
mut b := strings.new_builder(c.name.len + c.value.len + c.domain.len + c.path.len + extra_cookie_length)
|
mut b := strings.new_builder(c.name.len + c.value.len + c.domain.len + c.path.len +
|
||||||
|
extra_cookie_length)
|
||||||
b.write_string(c.name)
|
b.write_string(c.name)
|
||||||
b.write_string('=')
|
b.write_string('=')
|
||||||
b.write_string(sanitize_cookie_value(c.value))
|
b.write_string(sanitize_cookie_value(c.value))
|
||||||
|
@ -229,7 +230,7 @@ pub fn (c &Cookie) str() string {
|
||||||
}
|
}
|
||||||
if c.expires.year > 1600 {
|
if c.expires.year > 1600 {
|
||||||
e := c.expires
|
e := c.expires
|
||||||
time_str := '${e.weekday_str()}, ${e.day.str()} ${e.smonth()} ${e.year} ${e.hhmmss()} GMT'
|
time_str := '$e.weekday_str(), $e.day.str() $e.smonth() $e.year $e.hhmmss() GMT'
|
||||||
b.write_string('; expires=')
|
b.write_string('; expires=')
|
||||||
b.write_string(time_str)
|
b.write_string(time_str)
|
||||||
}
|
}
|
||||||
|
@ -264,9 +265,9 @@ pub fn (c &Cookie) str() string {
|
||||||
return b.str()
|
return b.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanitize(valid fn(byte) bool, v string) string {
|
fn sanitize(valid fn (byte) bool, v string) string {
|
||||||
mut ok := true
|
mut ok := true
|
||||||
for i in 0..v.len {
|
for i in 0 .. v.len {
|
||||||
if valid(v[i]) {
|
if valid(v[i]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -370,7 +371,7 @@ pub fn is_cookie_domain_name(_s string) bool {
|
||||||
}
|
}
|
||||||
part_len = 0
|
part_len = 0
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
last = c
|
last = c
|
||||||
}
|
}
|
||||||
|
@ -386,7 +387,7 @@ fn parse_cookie_value(_raw string, allow_double_quote bool) ?string {
|
||||||
if allow_double_quote && raw.len > 1 && raw[0] == `"` && raw[raw.len - 1] == `"` {
|
if allow_double_quote && raw.len > 1 && raw[0] == `"` && raw[raw.len - 1] == `"` {
|
||||||
raw = raw.substr(1, raw.len - 1)
|
raw = raw.substr(1, raw.len - 1)
|
||||||
}
|
}
|
||||||
for i in 0..raw.len {
|
for i in 0 .. raw.len {
|
||||||
if !valid_cookie_value_byte(raw[i]) {
|
if !valid_cookie_value_byte(raw[i]) {
|
||||||
return error('http.cookie: invalid cookie value')
|
return error('http.cookie: invalid cookie value')
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,43 +2,66 @@ import net.http
|
||||||
|
|
||||||
struct SetCookieTestCase {
|
struct SetCookieTestCase {
|
||||||
cookie &http.Cookie
|
cookie &http.Cookie
|
||||||
raw string
|
raw string
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReadSetCookiesTestCase {
|
struct ReadSetCookiesTestCase {
|
||||||
header map[string][]string
|
header map[string][]string
|
||||||
cookies []&http.Cookie
|
cookies []&http.Cookie
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AddCookieTestCase {
|
struct AddCookieTestCase {
|
||||||
cookie []&http.Cookie
|
cookie []&http.Cookie
|
||||||
raw string
|
raw string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
write_set_cookie_tests = [
|
write_set_cookie_tests = [
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-1', value: 'v1'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-1'
|
||||||
|
value: 'v1'
|
||||||
|
}
|
||||||
raw: 'cookie-1=v1'
|
raw: 'cookie-1=v1'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-2', value: 'two', max_age: 3600},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-2'
|
||||||
|
value: 'two'
|
||||||
|
max_age: 3600
|
||||||
|
}
|
||||||
raw: 'cookie-2=two; Max-Age=3600'
|
raw: 'cookie-2=two; Max-Age=3600'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-3', value: 'three', domain: '.example.com'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-3'
|
||||||
|
value: 'three'
|
||||||
|
domain: '.example.com'
|
||||||
|
}
|
||||||
raw: 'cookie-3=three; domain=example.com'
|
raw: 'cookie-3=three; domain=example.com'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-4', value: 'four', path: '/restricted/'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-4'
|
||||||
|
value: 'four'
|
||||||
|
path: '/restricted/'
|
||||||
|
}
|
||||||
raw: 'cookie-4=four; path=/restricted/'
|
raw: 'cookie-4=four; path=/restricted/'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-5', value: 'five', domain: 'wrong;bad.abc'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-5'
|
||||||
|
value: 'five'
|
||||||
|
domain: 'wrong;bad.abc'
|
||||||
|
}
|
||||||
raw: 'cookie-5=five'
|
raw: 'cookie-5=five'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-6', value: 'six', domain: 'bad-.abc'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-6'
|
||||||
|
value: 'six'
|
||||||
|
domain: 'bad-.abc'
|
||||||
|
}
|
||||||
raw: 'cookie-6=six'
|
raw: 'cookie-6=six'
|
||||||
},
|
},
|
||||||
// SetCookieTestCase{
|
// SetCookieTestCase{
|
||||||
|
@ -46,7 +69,11 @@ const (
|
||||||
// raw: 'cookie-7=seven; domain=127.0.0.1'
|
// raw: 'cookie-7=seven; domain=127.0.0.1'
|
||||||
// },
|
// },
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-8', value: 'eight', domain: '::1'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-8'
|
||||||
|
value: 'eight'
|
||||||
|
domain: '::1'
|
||||||
|
}
|
||||||
raw: 'cookie-8=eight'
|
raw: 'cookie-8=eight'
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
|
@ -63,106 +90,181 @@ const (
|
||||||
// raw: 'cookie-11=invalid-expiry'
|
// raw: 'cookie-11=invalid-expiry'
|
||||||
// },
|
// },
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-12', value: 'samesite-default', same_site: .same_site_default_mode},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-12'
|
||||||
|
value: 'samesite-default'
|
||||||
|
same_site: .same_site_default_mode
|
||||||
|
}
|
||||||
raw: 'cookie-12=samesite-default; SameSite'
|
raw: 'cookie-12=samesite-default; SameSite'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-13', value: 'samesite-lax', same_site: .same_site_lax_mode},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-13'
|
||||||
|
value: 'samesite-lax'
|
||||||
|
same_site: .same_site_lax_mode
|
||||||
|
}
|
||||||
raw: 'cookie-13=samesite-lax; SameSite=Lax'
|
raw: 'cookie-13=samesite-lax; SameSite=Lax'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-14', value: 'samesite-strict', same_site: .same_site_strict_mode},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-14'
|
||||||
|
value: 'samesite-strict'
|
||||||
|
same_site: .same_site_strict_mode
|
||||||
|
}
|
||||||
raw: 'cookie-14=samesite-strict; SameSite=Strict'
|
raw: 'cookie-14=samesite-strict; SameSite=Strict'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'cookie-15', value: 'samesite-none', same_site: .same_site_none_mode},
|
cookie: &http.Cookie{
|
||||||
|
name: 'cookie-15'
|
||||||
|
value: 'samesite-none'
|
||||||
|
same_site: .same_site_none_mode
|
||||||
|
}
|
||||||
raw: 'cookie-15=samesite-none; SameSite=None'
|
raw: 'cookie-15=samesite-none; SameSite=None'
|
||||||
},
|
},
|
||||||
// The 'special' cookies have values containing commas or spaces which
|
// The 'special' cookies have values containing commas or spaces which
|
||||||
// are disallowed by RFC 6265 but are common in the wild.
|
// are disallowed by RFC 6265 but are common in the wild.
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-1', value: 'a z'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-1'
|
||||||
|
value: 'a z'
|
||||||
|
}
|
||||||
raw: 'special-1=a z'
|
raw: 'special-1=a z'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-2', value: ' z'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-2'
|
||||||
|
value: ' z'
|
||||||
|
}
|
||||||
raw: 'special-2=" z"'
|
raw: 'special-2=" z"'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-3', value: 'a '},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-3'
|
||||||
|
value: 'a '
|
||||||
|
}
|
||||||
raw: 'special-3="a "'
|
raw: 'special-3="a "'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-4', value: ' '},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-4'
|
||||||
|
value: ' '
|
||||||
|
}
|
||||||
raw: 'special-4=" "'
|
raw: 'special-4=" "'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-5', value: 'a,z'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-5'
|
||||||
|
value: 'a,z'
|
||||||
|
}
|
||||||
raw: 'special-5=a,z'
|
raw: 'special-5=a,z'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-6', value: ',z'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-6'
|
||||||
|
value: ',z'
|
||||||
|
}
|
||||||
raw: 'special-6=",z"'
|
raw: 'special-6=",z"'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-7', value: 'a,'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-7'
|
||||||
|
value: 'a,'
|
||||||
|
}
|
||||||
raw: 'special-7="a,"'
|
raw: 'special-7="a,"'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'special-8', value: ','},
|
cookie: &http.Cookie{
|
||||||
|
name: 'special-8'
|
||||||
|
value: ','
|
||||||
|
}
|
||||||
raw: 'special-8=","'
|
raw: 'special-8=","'
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'empty-value', value: ''},
|
cookie: &http.Cookie{
|
||||||
|
name: 'empty-value'
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
raw: 'empty-value='
|
raw: 'empty-value='
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: ''},
|
cookie: &http.Cookie{
|
||||||
|
name: ''
|
||||||
|
}
|
||||||
raw: ''
|
raw: ''
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: '\t'},
|
cookie: &http.Cookie{
|
||||||
|
name: '\t'
|
||||||
|
}
|
||||||
raw: ''
|
raw: ''
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: '\r'},
|
cookie: &http.Cookie{
|
||||||
|
name: '\r'
|
||||||
|
}
|
||||||
raw: ''
|
raw: ''
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'a\nb', value: 'v'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'a\nb'
|
||||||
|
value: 'v'
|
||||||
|
}
|
||||||
raw: ''
|
raw: ''
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'a\nb', value: 'v'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'a\nb'
|
||||||
|
value: 'v'
|
||||||
|
}
|
||||||
raw: ''
|
raw: ''
|
||||||
},
|
},
|
||||||
SetCookieTestCase{
|
SetCookieTestCase{
|
||||||
cookie: &http.Cookie{name: 'a\rb', value: 'v'},
|
cookie: &http.Cookie{
|
||||||
|
name: 'a\rb'
|
||||||
|
value: 'v'
|
||||||
|
}
|
||||||
raw: ''
|
raw: ''
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
add_cookies_tests = [
|
add_cookies_tests = [
|
||||||
AddCookieTestCase{
|
AddCookieTestCase{
|
||||||
cookie: [],
|
cookie: []
|
||||||
raw: ""
|
raw: ''
|
||||||
},
|
},
|
||||||
AddCookieTestCase{
|
AddCookieTestCase{
|
||||||
cookie: [&http.Cookie{name: "cookie-1", value: "v1"}],
|
cookie: [&http.Cookie{
|
||||||
raw: "cookie-1=v1"
|
name: 'cookie-1'
|
||||||
|
value: 'v1'
|
||||||
|
}]
|
||||||
|
raw: 'cookie-1=v1'
|
||||||
},
|
},
|
||||||
AddCookieTestCase{
|
AddCookieTestCase{
|
||||||
cookie: [
|
cookie: [&http.Cookie{
|
||||||
&http.Cookie{name: "cookie-1", value: "v1"},
|
name: 'cookie-1'
|
||||||
&http.Cookie{name: "cookie-2", value: "v2"},
|
value: 'v1'
|
||||||
&http.Cookie{name: "cookie-3", value: "v3"}
|
},
|
||||||
],
|
&http.Cookie{
|
||||||
raw: "cookie-1=v1; cookie-2=v2; cookie-3=v3"
|
name: 'cookie-2'
|
||||||
}
|
value: 'v2'
|
||||||
|
},
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'cookie-3'
|
||||||
|
value: 'v3'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
raw: 'cookie-1=v1; cookie-2=v2; cookie-3=v3'
|
||||||
|
},
|
||||||
]
|
]
|
||||||
read_set_cookies_tests = [
|
read_set_cookies_tests = [
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ["Cookie-1=v1"]},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "Cookie-1", value: "v1", raw: "Cookie-1=v1"}]
|
'Set-Cookie': ['Cookie-1=v1']
|
||||||
|
}
|
||||||
|
cookies: [&http.Cookie{
|
||||||
|
name: 'Cookie-1'
|
||||||
|
value: 'v1'
|
||||||
|
raw: 'Cookie-1=v1'
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
// ReadSetCookiesTestCase{
|
// ReadSetCookiesTestCase{
|
||||||
// header: {"Set-Cookie": ["NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly"]},
|
// header: {"Set-Cookie": ["NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly"]},
|
||||||
|
@ -190,83 +292,158 @@ const (
|
||||||
// }]
|
// }]
|
||||||
// },
|
// },
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ["ASP.NET_SessionId=foo; path=/; HttpOnly"]},
|
header: map{
|
||||||
cookies: [&http.Cookie{
|
'Set-Cookie': ['ASP.NET_SessionId=foo; path=/; HttpOnly']
|
||||||
name: "ASP.NET_SessionId",
|
}
|
||||||
value: "foo",
|
cookies: [
|
||||||
path: "/",
|
&http.Cookie{
|
||||||
http_only: true,
|
name: 'ASP.NET_SessionId'
|
||||||
raw: "ASP.NET_SessionId=foo; path=/; HttpOnly"
|
value: 'foo'
|
||||||
}]
|
path: '/'
|
||||||
|
http_only: true
|
||||||
|
raw: 'ASP.NET_SessionId=foo; path=/; HttpOnly'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ["samesitedefault=foo; SameSite"]},
|
header: map{
|
||||||
cookies: [&http.Cookie{
|
'Set-Cookie': ['samesitedefault=foo; SameSite']
|
||||||
name: "samesitedefault",
|
}
|
||||||
value: "foo",
|
cookies: [
|
||||||
same_site: .same_site_default_mode,
|
&http.Cookie{
|
||||||
raw: "samesitedefault=foo; SameSite"
|
name: 'samesitedefault'
|
||||||
}]
|
value: 'foo'
|
||||||
|
same_site: .same_site_default_mode
|
||||||
|
raw: 'samesitedefault=foo; SameSite'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ["samesitelax=foo; SameSite=Lax"]},
|
header: map{
|
||||||
cookies: [&http.Cookie{
|
'Set-Cookie': ['samesitelax=foo; SameSite=Lax']
|
||||||
name: "samesitelax",
|
}
|
||||||
value: "foo",
|
cookies: [
|
||||||
same_site: .same_site_lax_mode,
|
&http.Cookie{
|
||||||
raw: "samesitelax=foo; SameSite=Lax"
|
name: 'samesitelax'
|
||||||
}]
|
value: 'foo'
|
||||||
|
same_site: .same_site_lax_mode
|
||||||
|
raw: 'samesitelax=foo; SameSite=Lax'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ["samesitestrict=foo; SameSite=Strict"]},
|
header: map{
|
||||||
cookies: [&http.Cookie{
|
'Set-Cookie': ['samesitestrict=foo; SameSite=Strict']
|
||||||
name: "samesitestrict",
|
}
|
||||||
value: "foo",
|
cookies: [
|
||||||
same_site: .same_site_strict_mode,
|
&http.Cookie{
|
||||||
raw: "samesitestrict=foo; SameSite=Strict"
|
name: 'samesitestrict'
|
||||||
}]
|
value: 'foo'
|
||||||
|
same_site: .same_site_strict_mode
|
||||||
|
raw: 'samesitestrict=foo; SameSite=Strict'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ["samesitenone=foo; SameSite=None"]},
|
header: map{
|
||||||
cookies: [&http.Cookie{
|
'Set-Cookie': ['samesitenone=foo; SameSite=None']
|
||||||
name: "samesitenone",
|
}
|
||||||
value: "foo",
|
cookies: [
|
||||||
same_site: .same_site_none_mode,
|
&http.Cookie{
|
||||||
raw: "samesitenone=foo; SameSite=None"
|
name: 'samesitenone'
|
||||||
}]
|
value: 'foo'
|
||||||
|
same_site: .same_site_none_mode
|
||||||
|
raw: 'samesitenone=foo; SameSite=None'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
// Make sure we can properly read back the Set-Cookie headers we create
|
// Make sure we can properly read back the Set-Cookie headers we create
|
||||||
// for values containing spaces or commas:
|
// for values containing spaces or commas:
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ['special-1=a z']},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "special-1", value: "a z", raw: 'special-1=a z'}]
|
'Set-Cookie': ['special-1=a z']
|
||||||
|
}
|
||||||
|
cookies: [
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'special-1'
|
||||||
|
value: 'a z'
|
||||||
|
raw: 'special-1=a z'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ['special-2=" z"']},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "special-2", value: " z", raw: 'special-2=" z"'}]
|
'Set-Cookie': ['special-2=" z"']
|
||||||
},
|
}
|
||||||
|
cookies: [
|
||||||
ReadSetCookiesTestCase{
|
&http.Cookie{
|
||||||
header: {"Set-Cookie": ['special-3="a "']},
|
name: 'special-2'
|
||||||
cookies: [&http.Cookie{name: "special-3", value: "a ", raw: 'special-3="a "'}]
|
value: ' z'
|
||||||
|
raw: 'special-2=" z"'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ['special-4=" "']},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "special-4", value: " ", raw: 'special-4=" "'}]
|
'Set-Cookie': ['special-3="a "']
|
||||||
|
}
|
||||||
|
cookies: [
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'special-3'
|
||||||
|
value: 'a '
|
||||||
|
raw: 'special-3="a "'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ['special-5=a,z']},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "special-5", value: "a,z", raw: 'special-5=a,z'}]
|
'Set-Cookie': ['special-4=" "']
|
||||||
|
}
|
||||||
|
cookies: [
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'special-4'
|
||||||
|
value: ' '
|
||||||
|
raw: 'special-4=" "'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ['special-6=",z"']},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "special-6", value: ",z", raw: 'special-6=",z"'}]
|
'Set-Cookie': ['special-5=a,z']
|
||||||
|
}
|
||||||
|
cookies: [
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'special-5'
|
||||||
|
value: 'a,z'
|
||||||
|
raw: 'special-5=a,z'
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ReadSetCookiesTestCase{
|
ReadSetCookiesTestCase{
|
||||||
header: {"Set-Cookie": ['special-7=","']},
|
header: map{
|
||||||
cookies: [&http.Cookie{name: "special-7", value: ",", raw: 'special-8=","'}]
|
'Set-Cookie': ['special-6=",z"']
|
||||||
|
}
|
||||||
|
cookies: [
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'special-6'
|
||||||
|
value: ',z'
|
||||||
|
raw: 'special-6=",z"'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
ReadSetCookiesTestCase{
|
||||||
|
header: map{
|
||||||
|
'Set-Cookie': ['special-7=","']
|
||||||
|
}
|
||||||
|
cookies: [
|
||||||
|
&http.Cookie{
|
||||||
|
name: 'special-7'
|
||||||
|
value: ','
|
||||||
|
raw: 'special-8=","'
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
// TODO(bradfitz): users have reported seeing this in the
|
// TODO(bradfitz): users have reported seeing this in the,,
|
||||||
// wild, but do browsers handle it? RFC 6265 just says "don't
|
// wild, but do browsers handle it? RFC 6265 just says "don't
|
||||||
// do that" (section 3) and then never mentions header folding
|
// do that" (section 3) and then never mentions header folding
|
||||||
// again.
|
// again.
|
||||||
|
|
|
@ -21,10 +21,10 @@ fn download_cb(ptr voidptr, size size_t, nmemb size_t, userp voidptr) {
|
||||||
data.cb(data.written)
|
data.cb(data.written)
|
||||||
//#data->cb(data->written); // TODO
|
//#data->cb(data->written); // TODO
|
||||||
return written
|
return written
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn download_file_with_progress(url string, out string, cb DownloadFn, cb_finished fn()) {
|
pub fn download_file_with_progress(url string, out string, cb DownloadFn, cb_finished fn ()) {
|
||||||
/*
|
/*
|
||||||
curl := C.curl_easy_init()
|
curl := C.curl_easy_init()
|
||||||
if isnil(curl) {
|
if isnil(curl) {
|
||||||
|
@ -45,7 +45,7 @@ pub fn download_file_with_progress(url string, out string, cb DownloadFn, cb_fin
|
||||||
C.curl_easy_cleanup(curl)
|
C.curl_easy_cleanup(curl)
|
||||||
C.fclose(fp)
|
C.fclose(fp)
|
||||||
cb_finished()
|
cb_finished()
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty() {
|
fn empty() {
|
||||||
|
|
|
@ -578,9 +578,9 @@ fn (mut h Header) add_key(key string) {
|
||||||
|
|
||||||
// Custom error struct for invalid header tokens
|
// Custom error struct for invalid header tokens
|
||||||
struct HeaderKeyError {
|
struct HeaderKeyError {
|
||||||
msg string
|
msg string
|
||||||
code int
|
code int
|
||||||
header string
|
header string
|
||||||
invalid_char byte
|
invalid_char byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
module http
|
module http
|
||||||
|
|
||||||
fn test_header_new() {
|
fn test_header_new() {
|
||||||
h := http.new_header(
|
h := new_header({ key: .accept, value: 'nothing' },
|
||||||
{key: .accept, value: 'nothing'},
|
key: .expires
|
||||||
{key: .expires, value: 'yesterday'}
|
value: 'yesterday'
|
||||||
)
|
)
|
||||||
assert h.contains(.accept)
|
assert h.contains(.accept)
|
||||||
assert h.contains(.expires)
|
assert h.contains(.expires)
|
||||||
|
@ -14,21 +14,21 @@ fn test_header_new() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_header_invalid_key() {
|
fn test_header_invalid_key() {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('space is invalid', ':(') or { return }
|
h.add_custom('space is invalid', ':(') or { return }
|
||||||
panic('should have returned')
|
panic('should have returned')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_header_adds_multiple() {
|
fn test_header_adds_multiple() {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add(.accept, 'one')
|
h.add(.accept, 'one')
|
||||||
h.add(.accept, 'two')
|
h.add(.accept, 'two')
|
||||||
|
|
||||||
assert h.values(.accept) == ['one' 'two']
|
assert h.values(.accept) == ['one', 'two']
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_header_get() ? {
|
fn test_header_get() ? {
|
||||||
mut h := http.new_header(key: .dnt, value: 'one')
|
mut h := new_header(key: .dnt, value: 'one')
|
||||||
h.add_custom('dnt', 'two') ?
|
h.add_custom('dnt', 'two') ?
|
||||||
dnt := h.get_custom('dnt') or { '' }
|
dnt := h.get_custom('dnt') or { '' }
|
||||||
exact := h.get_custom('dnt', exact: true) or { '' }
|
exact := h.get_custom('dnt', exact: true) or { '' }
|
||||||
|
@ -37,27 +37,27 @@ fn test_header_get() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_header_set() ? {
|
fn test_header_set() ? {
|
||||||
mut h := http.new_header(
|
mut h := new_header({ key: .dnt, value: 'one' },
|
||||||
{key: .dnt, value: 'one'},
|
key: .dnt
|
||||||
{key: .dnt, value: 'two'}
|
value: 'two'
|
||||||
)
|
)
|
||||||
assert h.values(.dnt) == ['one' 'two']
|
assert h.values(.dnt) == ['one', 'two']
|
||||||
h.set_custom('DNT', 'three') ?
|
h.set_custom('DNT', 'three') ?
|
||||||
assert h.values(.dnt) == ['three']
|
assert h.values(.dnt) == ['three']
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_header_delete() {
|
fn test_header_delete() {
|
||||||
mut h := http.new_header(
|
mut h := new_header({ key: .dnt, value: 'one' },
|
||||||
{key: .dnt, value: 'one'},
|
key: .dnt
|
||||||
{key: .dnt, value: 'two'}
|
value: 'two'
|
||||||
)
|
)
|
||||||
assert h.values(.dnt) == ['one' 'two']
|
assert h.values(.dnt) == ['one', 'two']
|
||||||
h.delete(.dnt)
|
h.delete(.dnt)
|
||||||
assert h.values(.dnt) == []
|
assert h.values(.dnt) == []
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_header_delete_not_existing() {
|
fn test_header_delete_not_existing() {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
assert h.data.len == 0
|
assert h.data.len == 0
|
||||||
assert h.keys.len == 0
|
assert h.keys.len == 0
|
||||||
h.delete(.dnt)
|
h.delete(.dnt)
|
||||||
|
@ -66,7 +66,7 @@ fn test_header_delete_not_existing() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_custom_header() ? {
|
fn test_custom_header() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('AbC', 'dEf') ?
|
h.add_custom('AbC', 'dEf') ?
|
||||||
h.add_custom('aBc', 'GhI') ?
|
h.add_custom('aBc', 'GhI') ?
|
||||||
assert h.custom_values('AbC', exact: true) == ['dEf']
|
assert h.custom_values('AbC', exact: true) == ['dEf']
|
||||||
|
@ -90,7 +90,7 @@ fn test_custom_header() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_contains_custom() ? {
|
fn test_contains_custom() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('Hello', 'world') ?
|
h.add_custom('Hello', 'world') ?
|
||||||
assert h.contains_custom('hello')
|
assert h.contains_custom('hello')
|
||||||
assert h.contains_custom('HELLO')
|
assert h.contains_custom('HELLO')
|
||||||
|
@ -100,7 +100,7 @@ fn test_contains_custom() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_get_custom() ? {
|
fn test_get_custom() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('Hello', 'world') ?
|
h.add_custom('Hello', 'world') ?
|
||||||
assert h.get_custom('hello') ? == 'world'
|
assert h.get_custom('hello') ? == 'world'
|
||||||
assert h.get_custom('HELLO') ? == 'world'
|
assert h.get_custom('HELLO') ? == 'world'
|
||||||
|
@ -116,7 +116,7 @@ fn test_get_custom() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_starting_with() ? {
|
fn test_starting_with() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('Hello-1', 'world') ?
|
h.add_custom('Hello-1', 'world') ?
|
||||||
h.add_custom('Hello-21', 'world') ?
|
h.add_custom('Hello-21', 'world') ?
|
||||||
assert h.starting_with('Hello-') ? == 'Hello-1'
|
assert h.starting_with('Hello-') ? == 'Hello-1'
|
||||||
|
@ -124,7 +124,7 @@ fn test_starting_with() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_custom_values() ? {
|
fn test_custom_values() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('Hello', 'world') ?
|
h.add_custom('Hello', 'world') ?
|
||||||
assert h.custom_values('hello') == ['world']
|
assert h.custom_values('hello') == ['world']
|
||||||
assert h.custom_values('HELLO') == ['world']
|
assert h.custom_values('HELLO') == ['world']
|
||||||
|
@ -134,7 +134,7 @@ fn test_custom_values() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_coerce() ? {
|
fn test_coerce() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('accept', 'foo') ?
|
h.add_custom('accept', 'foo') ?
|
||||||
h.add(.accept, 'bar')
|
h.add(.accept, 'bar')
|
||||||
assert h.values(.accept) == ['foo', 'bar']
|
assert h.values(.accept) == ['foo', 'bar']
|
||||||
|
@ -146,7 +146,7 @@ fn test_coerce() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_coerce_canonicalize() ? {
|
fn test_coerce_canonicalize() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('accept', 'foo') ?
|
h.add_custom('accept', 'foo') ?
|
||||||
h.add(.accept, 'bar')
|
h.add(.accept, 'bar')
|
||||||
assert h.values(.accept) == ['foo', 'bar']
|
assert h.values(.accept) == ['foo', 'bar']
|
||||||
|
@ -158,7 +158,7 @@ fn test_coerce_canonicalize() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_coerce_custom() ? {
|
fn test_coerce_custom() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('Hello', 'foo') ?
|
h.add_custom('Hello', 'foo') ?
|
||||||
h.add_custom('hello', 'bar') ?
|
h.add_custom('hello', 'bar') ?
|
||||||
h.add_custom('HELLO', 'baz') ?
|
h.add_custom('HELLO', 'baz') ?
|
||||||
|
@ -171,7 +171,7 @@ fn test_coerce_custom() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_coerce_canonicalize_custom() ? {
|
fn test_coerce_canonicalize_custom() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('foo-BAR', 'foo') ?
|
h.add_custom('foo-BAR', 'foo') ?
|
||||||
h.add_custom('FOO-bar', 'bar') ?
|
h.add_custom('FOO-bar', 'bar') ?
|
||||||
assert h.custom_values('foo-bar') == ['foo', 'bar']
|
assert h.custom_values('foo-bar') == ['foo', 'bar']
|
||||||
|
@ -183,7 +183,7 @@ fn test_coerce_canonicalize_custom() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_render_version() ? {
|
fn test_render_version() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('accept', 'foo') ?
|
h.add_custom('accept', 'foo') ?
|
||||||
h.add_custom('Accept', 'bar') ?
|
h.add_custom('Accept', 'bar') ?
|
||||||
h.add(.accept, 'baz')
|
h.add(.accept, 'baz')
|
||||||
|
@ -202,7 +202,7 @@ fn test_render_version() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_render_coerce() ? {
|
fn test_render_coerce() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('accept', 'foo') ?
|
h.add_custom('accept', 'foo') ?
|
||||||
h.add_custom('Accept', 'bar') ?
|
h.add_custom('Accept', 'bar') ?
|
||||||
h.add(.accept, 'baz')
|
h.add(.accept, 'baz')
|
||||||
|
@ -222,7 +222,7 @@ fn test_render_coerce() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_render_canonicalize() ? {
|
fn test_render_canonicalize() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('accept', 'foo') ?
|
h.add_custom('accept', 'foo') ?
|
||||||
h.add_custom('Accept', 'bar') ?
|
h.add_custom('Accept', 'bar') ?
|
||||||
h.add(.accept, 'baz')
|
h.add(.accept, 'baz')
|
||||||
|
@ -245,7 +245,7 @@ fn test_render_canonicalize() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_render_coerce_canonicalize() ? {
|
fn test_render_coerce_canonicalize() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add_custom('accept', 'foo') ?
|
h.add_custom('accept', 'foo') ?
|
||||||
h.add_custom('Accept', 'bar') ?
|
h.add_custom('Accept', 'bar') ?
|
||||||
h.add(.accept, 'baz')
|
h.add(.accept, 'baz')
|
||||||
|
@ -265,7 +265,7 @@ fn test_render_coerce_canonicalize() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_str() ? {
|
fn test_str() ? {
|
||||||
mut h := http.new_header()
|
mut h := new_header()
|
||||||
h.add(.accept, 'text/html')
|
h.add(.accept, 'text/html')
|
||||||
h.add_custom('Accept', 'image/jpeg') ?
|
h.add_custom('Accept', 'image/jpeg') ?
|
||||||
h.add_custom('X-custom', 'Hello') ?
|
h.add_custom('X-custom', 'Hello') ?
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module http //internal tests have access to *everything in the module*
|
module http
|
||||||
|
|
||||||
|
// internal tests have access to *everything in the module*
|
||||||
import json
|
import json
|
||||||
|
|
||||||
struct HttpbinResponseBody {
|
struct HttpbinResponseBody {
|
||||||
|
@ -13,7 +14,6 @@ struct HttpbinResponseBody {
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
|
fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
|
||||||
url := 'https://httpbin.org/'
|
url := 'https://httpbin.org/'
|
||||||
methods := if _methods.len == 0 { ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'] } else { _methods }
|
methods := if _methods.len == 0 { ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'] } else { _methods }
|
||||||
|
@ -23,7 +23,7 @@ fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
|
||||||
for method in methods {
|
for method in methods {
|
||||||
lmethod := method.to_lower()
|
lmethod := method.to_lower()
|
||||||
config.method = method_from_str(method)
|
config.method = method_from_str(method)
|
||||||
res := fetch(url + lmethod, config)?
|
res := fetch(url + lmethod, config) ?
|
||||||
// TODO
|
// TODO
|
||||||
// body := json.decode(HttpbinResponseBody,res.text)?
|
// body := json.decode(HttpbinResponseBody,res.text)?
|
||||||
result << res
|
result << res
|
||||||
|
@ -32,40 +32,38 @@ fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_fetch_bare() {
|
fn test_http_fetch_bare() {
|
||||||
$if !network ? { return }
|
$if !network ? {
|
||||||
responses := http_fetch_mock([], FetchConfig{}) or {
|
return
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
responses := http_fetch_mock([], FetchConfig{}) or { panic(err) }
|
||||||
for response in responses {
|
for response in responses {
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_fetch_with_data() {
|
fn test_http_fetch_with_data() {
|
||||||
$if !network ? { return }
|
$if !network ? {
|
||||||
responses := http_fetch_mock(['POST', 'PUT', 'PATCH', 'DELETE'], {
|
return
|
||||||
data: 'hello world'
|
|
||||||
}) or {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
responses := http_fetch_mock(['POST', 'PUT', 'PATCH', 'DELETE'],
|
||||||
|
data: 'hello world'
|
||||||
|
) or { panic(err) }
|
||||||
for response in responses {
|
for response in responses {
|
||||||
payload := json.decode(HttpbinResponseBody,response.text) or {
|
payload := json.decode(HttpbinResponseBody, response.text) or { panic(err) }
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
assert payload.data == 'hello world'
|
assert payload.data == 'hello world'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_fetch_with_params() {
|
fn test_http_fetch_with_params() {
|
||||||
$if !network ? { return }
|
$if !network ? {
|
||||||
responses := http_fetch_mock([], {
|
return
|
||||||
params: {
|
}
|
||||||
'a': 'b',
|
responses := http_fetch_mock([],
|
||||||
|
params: map{
|
||||||
|
'a': 'b'
|
||||||
'c': 'd'
|
'c': 'd'
|
||||||
}
|
}
|
||||||
}) or {
|
) or { panic(err) }
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for response in responses {
|
for response in responses {
|
||||||
// payload := json.decode(HttpbinResponseBody,response.text) or {
|
// payload := json.decode(HttpbinResponseBody,response.text) or {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
|
@ -78,14 +76,14 @@ fn test_http_fetch_with_params() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_fetch_with_headers() ? {
|
fn test_http_fetch_with_headers() ? {
|
||||||
$if !network ? { return }
|
$if !network ? {
|
||||||
|
return
|
||||||
|
}
|
||||||
mut header := new_header()
|
mut header := new_header()
|
||||||
header.add_custom('Test-Header', 'hello world') ?
|
header.add_custom('Test-Header', 'hello world') ?
|
||||||
responses := http_fetch_mock([], {
|
responses := http_fetch_mock([],
|
||||||
header: header
|
header: header
|
||||||
}) or {
|
) or { panic(err) }
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for response in responses {
|
for response in responses {
|
||||||
// payload := json.decode(HttpbinResponseBody,response.text) or {
|
// payload := json.decode(HttpbinResponseBody,response.text) or {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
|
|
|
@ -15,9 +15,7 @@ fn test_http_get_from_vlang_utc_now() {
|
||||||
urls := ['http://vlang.io/utc_now', 'https://vlang.io/utc_now']
|
urls := ['http://vlang.io/utc_now', 'https://vlang.io/utc_now']
|
||||||
for url in urls {
|
for url in urls {
|
||||||
println('Test getting current time from $url by http.get')
|
println('Test getting current time from $url by http.get')
|
||||||
res := http.get(url) or {
|
res := http.get(url) or { panic(err) }
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
assert 200 == res.status_code
|
assert 200 == res.status_code
|
||||||
assert res.text.len > 0
|
assert res.text.len > 0
|
||||||
assert res.text.int() > 1566403696
|
assert res.text.int() > 1566403696
|
||||||
|
@ -39,9 +37,7 @@ fn test_public_servers() {
|
||||||
]
|
]
|
||||||
for url in urls {
|
for url in urls {
|
||||||
println('Testing http.get on public url: $url ')
|
println('Testing http.get on public url: $url ')
|
||||||
res := http.get(url) or {
|
res := http.get(url) or { panic(err) }
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
assert 200 == res.status_code
|
assert 200 == res.status_code
|
||||||
assert res.text.len > 0
|
assert res.text.len > 0
|
||||||
}
|
}
|
||||||
|
@ -53,9 +49,7 @@ fn test_relative_redirects() {
|
||||||
} $else {
|
} $else {
|
||||||
return
|
return
|
||||||
} // tempfix periodic: httpbin relative redirects are broken
|
} // tempfix periodic: httpbin relative redirects are broken
|
||||||
res := http.get('https://httpbin.org/relative-redirect/3?abc=xyz') or {
|
res := http.get('https://httpbin.org/relative-redirect/3?abc=xyz') or { panic(err) }
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
assert 200 == res.status_code
|
assert 200 == res.status_code
|
||||||
assert res.text.len > 0
|
assert res.text.len > 0
|
||||||
assert res.text.contains('"abc": "xyz"')
|
assert res.text.contains('"abc": "xyz"')
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module http
|
module http
|
||||||
|
|
||||||
import chunked
|
import net.http.chunked
|
||||||
|
|
||||||
// Response represents the result of the request
|
// Response represents the result of the request
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
|
@ -23,9 +23,9 @@ fn (mut resp Response) free() {
|
||||||
pub fn (resp Response) bytes() []byte {
|
pub fn (resp Response) bytes() []byte {
|
||||||
// TODO: build []byte directly; this uses two allocations
|
// TODO: build []byte directly; this uses two allocations
|
||||||
// TODO: cookies
|
// TODO: cookies
|
||||||
return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' +
|
return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' + '${resp.header.render(
|
||||||
'${resp.header.render(version: resp.version)}\r\n' +
|
version: resp.version
|
||||||
'$resp.text').bytes()
|
)}\r\n' + '$resp.text').bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a raw HTTP response into a Response object
|
// Parse a raw HTTP response into a Response object
|
||||||
|
@ -66,7 +66,9 @@ pub fn parse_response(resp string) Response {
|
||||||
parts := cookie.split_nth('=', 2)
|
parts := cookie.split_nth('=', 2)
|
||||||
cookies[parts[0]] = parts[1]
|
cookies[parts[0]] = parts[1]
|
||||||
}
|
}
|
||||||
if header.get(.transfer_encoding) or { '' } == 'chunked' || header.get(.content_length) or { '' } == '' {
|
if header.get(.transfer_encoding) or { '' } == 'chunked' || header.get(.content_length) or {
|
||||||
|
''
|
||||||
|
} == '' {
|
||||||
text = chunked.decode(text)
|
text = chunked.decode(text)
|
||||||
}
|
}
|
||||||
return Response{
|
return Response{
|
||||||
|
|
|
@ -228,7 +228,9 @@ pub fn (code Status) str() string {
|
||||||
// int converts an assigned and known Status to its integral equivalent.
|
// int converts an assigned and known Status to its integral equivalent.
|
||||||
// if a Status is unknown or unassigned, this method will return zero
|
// if a Status is unknown or unassigned, this method will return zero
|
||||||
pub fn (code Status) int() int {
|
pub fn (code Status) int() int {
|
||||||
if code in [.unknown, .unassigned] { return 0 }
|
if code in [.unknown, .unassigned] {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return int(code)
|
return int(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue