diff --git a/cmd/tools/vtest-cleancode.v b/cmd/tools/vtest-cleancode.v index 09545cb5a3..1770b8dc66 100644 --- a/cmd/tools/vtest-cleancode.v +++ b/cmd/tools/vtest-cleancode.v @@ -44,7 +44,6 @@ const ( ] vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [ '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/regex/regex_test.v' /* contains meaningfull formatting of the test case data */, 'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */, diff --git a/vlib/net/address.v b/vlib/net/address.v index 3e2c1e18e7..47166167c6 100644 --- a/vlib/net/address.v +++ b/vlib/net/address.v @@ -100,13 +100,13 @@ const aoffset = __offsetof(Addr, addr) fn (a Addr) len() u32 { match a.family() { .ip { - return sizeof(Ip) + aoffset + return sizeof(Ip) + net.aoffset } .ip6 { - return sizeof(Ip6) + aoffset + return sizeof(Ip6) + net.aoffset } .unix { - return sizeof(Unix) + aoffset + return sizeof(Unix) + net.aoffset } else { panic('Unknown address family') diff --git a/vlib/net/address_test.v b/vlib/net/address_test.v index 3e07b14627..5b3aab0678 100644 --- a/vlib/net/address_test.v +++ b/vlib/net/address_test.v @@ -14,7 +14,7 @@ $if windows { } fn test_diagnostics() { - dump(net.aoffset) + dump(aoffset) eprintln('--------') in6 := C.sockaddr_in6{} our_ip6 := Ip6{} @@ -72,17 +72,17 @@ fn test_sizes_unix_sun_path() { } fn test_offsets_ipv6() { - assert __offsetof(C.sockaddr_in6, sin6_addr) == __offsetof(Ip6, addr) + net.aoffset - assert __offsetof(C.sockaddr_in6, sin6_port) == __offsetof(Ip6, port) + net.aoffset + assert __offsetof(C.sockaddr_in6, sin6_addr) == __offsetof(Ip6, addr) + aoffset + assert __offsetof(C.sockaddr_in6, sin6_port) == __offsetof(Ip6, port) + aoffset } fn test_offsets_ipv4() { - assert __offsetof(C.sockaddr_in, sin_addr) == __offsetof(Ip, addr) + net.aoffset - assert __offsetof(C.sockaddr_in, sin_port) == __offsetof(Ip, port) + net.aoffset + assert __offsetof(C.sockaddr_in, sin_addr) == __offsetof(Ip, addr) + aoffset + assert __offsetof(C.sockaddr_in, sin_port) == __offsetof(Ip, port) + aoffset } 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() { diff --git a/vlib/net/http/chunked/dechunk.v b/vlib/net/http/chunked/dechunk.v index 50a10717a4..0e82586e4c 100644 --- a/vlib/net/http/chunked/dechunk.v +++ b/vlib/net/http/chunked/dechunk.v @@ -7,6 +7,7 @@ import strings // followed by \r\n as a line separator, // followed by a chunk of data of the given size. // The end is marked with a chunk with size 0. + struct ChunkScanner { mut: pos int @@ -23,7 +24,7 @@ fn (mut s ChunkScanner) read_chunk_size() int { if !c.is_hex_digit() { break } - n = n<<4 + n = n << 4 n += int(unhex(c)) s.pos++ } @@ -33,11 +34,9 @@ fn (mut s ChunkScanner) read_chunk_size() int { fn unhex(c byte) byte { if `0` <= c && c <= `9` { return c - `0` - } - else if `a` <= c && c <= `f` { + } else if `a` <= c && c <= `f` { return c - `a` + 10 - } - else if `A` <= c && c <= `F` { + } else if `A` <= c && c <= `F` { return c - `A` + 10 } return 0 diff --git a/vlib/net/http/cookie.v b/vlib/net/http/cookie.v index c4e51421da..e678d93540 100644 --- a/vlib/net/http/cookie.v +++ b/vlib/net/http/cookie.v @@ -10,20 +10,21 @@ pub struct Cookie { pub mut: name string value string - path string // optional - domain string // optional + path string // optional + domain string // 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 delete cookie now, equivalently 'Max-Age: 0' // max_age>0 means Max-Age attribute present and given in seconds - max_age int - secure bool - http_only bool - same_site SameSite - raw string - unparsed []string // Raw text of unparsed attribute-value pairs + max_age int + secure bool + http_only bool + same_site SameSite + raw string + unparsed []string // Raw text of unparsed attribute-value pairs } + // 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 // 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) { continue } - value := parse_cookie_value(raw_value, true) or { - continue - } - mut c := &Cookie{ - name: name, - value: value, + value := parse_cookie_value(raw_value, true) or { continue } + mut c := &Cookie{ + name: name + value: value raw: line } for i, _ in parts { @@ -182,10 +181,11 @@ pub fn read_cookies(h map[string][]string, filter string) []&Cookie { if filter != '' && filter != name { continue } - val = parse_cookie_value(val, true) or { - continue + val = parse_cookie_value(val, true) or { continue } + cookies << &Cookie{ + name: name + value: val } - cookies << &Cookie{name: name, value: val} } } return cookies @@ -203,7 +203,8 @@ pub fn (c &Cookie) str() string { // extra_cookie_length derived from typical length of cookie attributes // see RFC 6265 Sec 4.1. 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('=') b.write_string(sanitize_cookie_value(c.value)) @@ -229,7 +230,7 @@ pub fn (c &Cookie) str() string { } if c.expires.year > 1600 { 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(time_str) } @@ -264,9 +265,9 @@ pub fn (c &Cookie) str() string { return b.str() } -fn sanitize(valid fn(byte) bool, v string) string { +fn sanitize(valid fn (byte) bool, v string) string { mut ok := true - for i in 0..v.len { + for i in 0 .. v.len { if valid(v[i]) { continue } @@ -370,7 +371,7 @@ pub fn is_cookie_domain_name(_s string) bool { } part_len = 0 } else { - return false + return false } 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] == `"` { 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]) { return error('http.cookie: invalid cookie value') } diff --git a/vlib/net/http/cookie_test.v b/vlib/net/http/cookie_test.v index a7667e2714..5fd3da2dfb 100644 --- a/vlib/net/http/cookie_test.v +++ b/vlib/net/http/cookie_test.v @@ -2,43 +2,66 @@ import net.http struct SetCookieTestCase { cookie &http.Cookie - raw string + raw string } struct ReadSetCookiesTestCase { - header map[string][]string + header map[string][]string cookies []&http.Cookie } struct AddCookieTestCase { cookie []&http.Cookie - raw string + raw string } const ( write_set_cookie_tests = [ SetCookieTestCase{ - cookie: &http.Cookie{name: 'cookie-1', value: 'v1'}, + cookie: &http.Cookie{ + name: 'cookie-1' + value: 'v1' + } raw: 'cookie-1=v1' }, 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' }, 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' }, 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/' }, 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' }, 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' }, // SetCookieTestCase{ @@ -46,7 +69,11 @@ const ( // raw: 'cookie-7=seven; domain=127.0.0.1' // }, 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' }, // { @@ -63,106 +90,181 @@ const ( // raw: 'cookie-11=invalid-expiry' // }, 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' }, 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' }, 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' }, 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' }, // The 'special' cookies have values containing commas or spaces which // are disallowed by RFC 6265 but are common in the wild. SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-1', value: 'a z'}, + cookie: &http.Cookie{ + name: 'special-1' + value: 'a z' + } raw: 'special-1=a z' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-2', value: ' z'}, + cookie: &http.Cookie{ + name: 'special-2' + value: ' z' + } raw: 'special-2=" z"' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-3', value: 'a '}, + cookie: &http.Cookie{ + name: 'special-3' + value: 'a ' + } raw: 'special-3="a "' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-4', value: ' '}, + cookie: &http.Cookie{ + name: 'special-4' + value: ' ' + } raw: 'special-4=" "' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-5', value: 'a,z'}, + cookie: &http.Cookie{ + name: 'special-5' + value: 'a,z' + } raw: 'special-5=a,z' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-6', value: ',z'}, + cookie: &http.Cookie{ + name: 'special-6' + value: ',z' + } raw: 'special-6=",z"' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-7', value: 'a,'}, + cookie: &http.Cookie{ + name: 'special-7' + value: 'a,' + } raw: 'special-7="a,"' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'special-8', value: ','}, + cookie: &http.Cookie{ + name: 'special-8' + value: ',' + } raw: 'special-8=","' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'empty-value', value: ''}, + cookie: &http.Cookie{ + name: 'empty-value' + value: '' + } raw: 'empty-value=' }, SetCookieTestCase{ - cookie: &http.Cookie{name: ''}, + cookie: &http.Cookie{ + name: '' + } raw: '' }, SetCookieTestCase{ - cookie: &http.Cookie{name: '\t'}, + cookie: &http.Cookie{ + name: '\t' + } raw: '' }, SetCookieTestCase{ - cookie: &http.Cookie{name: '\r'}, + cookie: &http.Cookie{ + name: '\r' + } raw: '' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'a\nb', value: 'v'}, + cookie: &http.Cookie{ + name: 'a\nb' + value: 'v' + } raw: '' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'a\nb', value: 'v'}, + cookie: &http.Cookie{ + name: 'a\nb' + value: 'v' + } raw: '' }, SetCookieTestCase{ - cookie: &http.Cookie{name: 'a\rb', value: 'v'}, + cookie: &http.Cookie{ + name: 'a\rb' + value: 'v' + } raw: '' }, ] add_cookies_tests = [ AddCookieTestCase{ - cookie: [], - raw: "" + cookie: [] + raw: '' }, AddCookieTestCase{ - cookie: [&http.Cookie{name: "cookie-1", value: "v1"}], - raw: "cookie-1=v1" + cookie: [&http.Cookie{ + name: 'cookie-1' + value: 'v1' + }] + raw: 'cookie-1=v1' }, AddCookieTestCase{ - cookie: [ - &http.Cookie{name: "cookie-1", value: "v1"}, - &http.Cookie{name: "cookie-2", value: "v2"}, - &http.Cookie{name: "cookie-3", value: "v3"} - ], - raw: "cookie-1=v1; cookie-2=v2; cookie-3=v3" - } + cookie: [&http.Cookie{ + name: 'cookie-1' + value: 'v1' + }, + &http.Cookie{ + 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 = [ ReadSetCookiesTestCase{ - header: {"Set-Cookie": ["Cookie-1=v1"]}, - cookies: [&http.Cookie{name: "Cookie-1", value: "v1", raw: "Cookie-1=v1"}] + header: map{ + 'Set-Cookie': ['Cookie-1=v1'] + } + cookies: [&http.Cookie{ + name: 'Cookie-1' + value: 'v1' + raw: 'Cookie-1=v1' + }] }, // ReadSetCookiesTestCase{ // 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{ - header: {"Set-Cookie": ["ASP.NET_SessionId=foo; path=/; HttpOnly"]}, - cookies: [&http.Cookie{ - name: "ASP.NET_SessionId", - value: "foo", - path: "/", - http_only: true, - raw: "ASP.NET_SessionId=foo; path=/; HttpOnly" - }] + header: map{ + 'Set-Cookie': ['ASP.NET_SessionId=foo; path=/; HttpOnly'] + } + cookies: [ + &http.Cookie{ + name: 'ASP.NET_SessionId' + value: 'foo' + path: '/' + http_only: true + raw: 'ASP.NET_SessionId=foo; path=/; HttpOnly' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ["samesitedefault=foo; SameSite"]}, - cookies: [&http.Cookie{ - name: "samesitedefault", - value: "foo", - same_site: .same_site_default_mode, - raw: "samesitedefault=foo; SameSite" - }] + header: map{ + 'Set-Cookie': ['samesitedefault=foo; SameSite'] + } + cookies: [ + &http.Cookie{ + name: 'samesitedefault' + value: 'foo' + same_site: .same_site_default_mode + raw: 'samesitedefault=foo; SameSite' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ["samesitelax=foo; SameSite=Lax"]}, - cookies: [&http.Cookie{ - name: "samesitelax", - value: "foo", - same_site: .same_site_lax_mode, - raw: "samesitelax=foo; SameSite=Lax" - }] + header: map{ + 'Set-Cookie': ['samesitelax=foo; SameSite=Lax'] + } + cookies: [ + &http.Cookie{ + name: 'samesitelax' + value: 'foo' + same_site: .same_site_lax_mode + raw: 'samesitelax=foo; SameSite=Lax' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ["samesitestrict=foo; SameSite=Strict"]}, - cookies: [&http.Cookie{ - name: "samesitestrict", - value: "foo", - same_site: .same_site_strict_mode, - raw: "samesitestrict=foo; SameSite=Strict" - }] + header: map{ + 'Set-Cookie': ['samesitestrict=foo; SameSite=Strict'] + } + cookies: [ + &http.Cookie{ + name: 'samesitestrict' + value: 'foo' + same_site: .same_site_strict_mode + raw: 'samesitestrict=foo; SameSite=Strict' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ["samesitenone=foo; SameSite=None"]}, - cookies: [&http.Cookie{ - name: "samesitenone", - value: "foo", - same_site: .same_site_none_mode, - raw: "samesitenone=foo; SameSite=None" - }] + header: map{ + 'Set-Cookie': ['samesitenone=foo; SameSite=None'] + } + cookies: [ + &http.Cookie{ + 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 // for values containing spaces or commas: ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-1=a z']}, - cookies: [&http.Cookie{name: "special-1", value: "a z", raw: 'special-1=a z'}] + header: map{ + 'Set-Cookie': ['special-1=a z'] + } + cookies: [ + &http.Cookie{ + name: 'special-1' + value: 'a z' + raw: 'special-1=a z' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-2=" z"']}, - cookies: [&http.Cookie{name: "special-2", value: " z", raw: 'special-2=" z"'}] - }, - - ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-3="a "']}, - cookies: [&http.Cookie{name: "special-3", value: "a ", raw: 'special-3="a "'}] + header: map{ + 'Set-Cookie': ['special-2=" z"'] + } + cookies: [ + &http.Cookie{ + name: 'special-2' + value: ' z' + raw: 'special-2=" z"' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-4=" "']}, - cookies: [&http.Cookie{name: "special-4", value: " ", raw: 'special-4=" "'}] + header: map{ + 'Set-Cookie': ['special-3="a "'] + } + cookies: [ + &http.Cookie{ + name: 'special-3' + value: 'a ' + raw: 'special-3="a "' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-5=a,z']}, - cookies: [&http.Cookie{name: "special-5", value: "a,z", raw: 'special-5=a,z'}] + header: map{ + 'Set-Cookie': ['special-4=" "'] + } + cookies: [ + &http.Cookie{ + name: 'special-4' + value: ' ' + raw: 'special-4=" "' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-6=",z"']}, - cookies: [&http.Cookie{name: "special-6", value: ",z", raw: 'special-6=",z"'}] + header: map{ + 'Set-Cookie': ['special-5=a,z'] + } + cookies: [ + &http.Cookie{ + name: 'special-5' + value: 'a,z' + raw: 'special-5=a,z' + }, + ] }, ReadSetCookiesTestCase{ - header: {"Set-Cookie": ['special-7=","']}, - cookies: [&http.Cookie{name: "special-7", value: ",", raw: 'special-8=","'}] + header: map{ + '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 // do that" (section 3) and then never mentions header folding // again. diff --git a/vlib/net/http/download_nix.c.v b/vlib/net/http/download_nix.c.v index 3d5b7de66c..724a256b52 100644 --- a/vlib/net/http/download_nix.c.v +++ b/vlib/net/http/download_nix.c.v @@ -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); // TODO 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() 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.fclose(fp) cb_finished() -*/ + */ } fn empty() { diff --git a/vlib/net/http/header.v b/vlib/net/http/header.v index bab883a069..923e7e7a40 100644 --- a/vlib/net/http/header.v +++ b/vlib/net/http/header.v @@ -578,9 +578,9 @@ fn (mut h Header) add_key(key string) { // Custom error struct for invalid header tokens struct HeaderKeyError { - msg string - code int - header string + msg string + code int + header string invalid_char byte } diff --git a/vlib/net/http/header_test.v b/vlib/net/http/header_test.v index a7ee6ea793..1b4eacb96d 100644 --- a/vlib/net/http/header_test.v +++ b/vlib/net/http/header_test.v @@ -1,9 +1,9 @@ module http fn test_header_new() { - h := http.new_header( - {key: .accept, value: 'nothing'}, - {key: .expires, value: 'yesterday'} + h := new_header({ key: .accept, value: 'nothing' }, + key: .expires + value: 'yesterday' ) assert h.contains(.accept) assert h.contains(.expires) @@ -14,21 +14,21 @@ fn test_header_new() { } fn test_header_invalid_key() { - mut h := http.new_header() + mut h := new_header() h.add_custom('space is invalid', ':(') or { return } panic('should have returned') } fn test_header_adds_multiple() { - mut h := http.new_header() + mut h := new_header() h.add(.accept, 'one') h.add(.accept, 'two') - assert h.values(.accept) == ['one' 'two'] + assert h.values(.accept) == ['one', 'two'] } 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') ? dnt := h.get_custom('dnt') or { '' } exact := h.get_custom('dnt', exact: true) or { '' } @@ -37,27 +37,27 @@ fn test_header_get() ? { } fn test_header_set() ? { - mut h := http.new_header( - {key: .dnt, value: 'one'}, - {key: .dnt, value: 'two'} + mut h := new_header({ key: .dnt, value: 'one' }, + key: .dnt + value: 'two' ) - assert h.values(.dnt) == ['one' 'two'] + assert h.values(.dnt) == ['one', 'two'] h.set_custom('DNT', 'three') ? assert h.values(.dnt) == ['three'] } fn test_header_delete() { - mut h := http.new_header( - {key: .dnt, value: 'one'}, - {key: .dnt, value: 'two'} + mut h := new_header({ key: .dnt, value: 'one' }, + key: .dnt + value: 'two' ) - assert h.values(.dnt) == ['one' 'two'] + assert h.values(.dnt) == ['one', 'two'] h.delete(.dnt) assert h.values(.dnt) == [] } fn test_header_delete_not_existing() { - mut h := http.new_header() + mut h := new_header() assert h.data.len == 0 assert h.keys.len == 0 h.delete(.dnt) @@ -66,7 +66,7 @@ fn test_header_delete_not_existing() { } fn test_custom_header() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('AbC', 'dEf') ? h.add_custom('aBc', 'GhI') ? assert h.custom_values('AbC', exact: true) == ['dEf'] @@ -90,7 +90,7 @@ fn test_custom_header() ? { } fn test_contains_custom() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('Hello', 'world') ? assert h.contains_custom('hello') assert h.contains_custom('HELLO') @@ -100,7 +100,7 @@ fn test_contains_custom() ? { } fn test_get_custom() ? { - mut h := http.new_header() + mut h := new_header() h.add_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() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('Hello-1', 'world') ? h.add_custom('Hello-21', 'world') ? assert h.starting_with('Hello-') ? == 'Hello-1' @@ -124,7 +124,7 @@ fn test_starting_with() ? { } fn test_custom_values() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('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() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('accept', 'foo') ? h.add(.accept, 'bar') assert h.values(.accept) == ['foo', 'bar'] @@ -146,7 +146,7 @@ fn test_coerce() ? { } fn test_coerce_canonicalize() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('accept', 'foo') ? h.add(.accept, 'bar') assert h.values(.accept) == ['foo', 'bar'] @@ -158,7 +158,7 @@ fn test_coerce_canonicalize() ? { } fn test_coerce_custom() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('Hello', 'foo') ? h.add_custom('hello', 'bar') ? h.add_custom('HELLO', 'baz') ? @@ -171,7 +171,7 @@ fn test_coerce_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', 'bar') ? assert h.custom_values('foo-bar') == ['foo', 'bar'] @@ -183,7 +183,7 @@ fn test_coerce_canonicalize_custom() ? { } fn test_render_version() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('accept', 'foo') ? h.add_custom('Accept', 'bar') ? h.add(.accept, 'baz') @@ -202,7 +202,7 @@ fn test_render_version() ? { } fn test_render_coerce() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('accept', 'foo') ? h.add_custom('Accept', 'bar') ? h.add(.accept, 'baz') @@ -222,7 +222,7 @@ fn test_render_coerce() ? { } fn test_render_canonicalize() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('accept', 'foo') ? h.add_custom('Accept', 'bar') ? h.add(.accept, 'baz') @@ -245,7 +245,7 @@ fn test_render_canonicalize() ? { } fn test_render_coerce_canonicalize() ? { - mut h := http.new_header() + mut h := new_header() h.add_custom('accept', 'foo') ? h.add_custom('Accept', 'bar') ? h.add(.accept, 'baz') @@ -265,7 +265,7 @@ fn test_render_coerce_canonicalize() ? { } fn test_str() ? { - mut h := http.new_header() + mut h := new_header() h.add(.accept, 'text/html') h.add_custom('Accept', 'image/jpeg') ? h.add_custom('X-custom', 'Hello') ? diff --git a/vlib/net/http/http_httpbin_test.v b/vlib/net/http/http_httpbin_test.v index 37a25eba19..f896ebc921 100644 --- a/vlib/net/http/http_httpbin_test.v +++ b/vlib/net/http/http_httpbin_test.v @@ -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 struct HttpbinResponseBody { @@ -13,7 +14,6 @@ struct HttpbinResponseBody { url string } - fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response { url := 'https://httpbin.org/' 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 { lmethod := method.to_lower() config.method = method_from_str(method) - res := fetch(url + lmethod, config)? + res := fetch(url + lmethod, config) ? // TODO // body := json.decode(HttpbinResponseBody,res.text)? result << res @@ -32,40 +32,38 @@ fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response { } fn test_http_fetch_bare() { - $if !network ? { return } - responses := http_fetch_mock([], FetchConfig{}) or { - panic(err) + $if !network ? { + return } + responses := http_fetch_mock([], FetchConfig{}) or { panic(err) } for response in responses { assert response.status_code == 200 } } fn test_http_fetch_with_data() { - $if !network ? { return } - responses := http_fetch_mock(['POST', 'PUT', 'PATCH', 'DELETE'], { - data: 'hello world' - }) or { - panic(err) + $if !network ? { + return } + responses := http_fetch_mock(['POST', 'PUT', 'PATCH', 'DELETE'], + data: 'hello world' + ) or { panic(err) } for response in responses { - payload := json.decode(HttpbinResponseBody,response.text) or { - panic(err) - } + payload := json.decode(HttpbinResponseBody, response.text) or { panic(err) } assert payload.data == 'hello world' } } fn test_http_fetch_with_params() { - $if !network ? { return } - responses := http_fetch_mock([], { - params: { - 'a': 'b', + $if !network ? { + return + } + responses := http_fetch_mock([], + params: map{ + 'a': 'b' 'c': 'd' } - }) or { - panic(err) - } + ) or { panic(err) } for response in responses { // payload := json.decode(HttpbinResponseBody,response.text) or { // panic(err) @@ -78,14 +76,14 @@ fn test_http_fetch_with_params() { } fn test_http_fetch_with_headers() ? { - $if !network ? { return } + $if !network ? { + return + } mut header := new_header() header.add_custom('Test-Header', 'hello world') ? - responses := http_fetch_mock([], { + responses := http_fetch_mock([], header: header - }) or { - panic(err) - } + ) or { panic(err) } for response in responses { // payload := json.decode(HttpbinResponseBody,response.text) or { // panic(err) diff --git a/vlib/net/http/http_test.v b/vlib/net/http/http_test.v index adc1c0aab6..0aa628e53e 100644 --- a/vlib/net/http/http_test.v +++ b/vlib/net/http/http_test.v @@ -15,9 +15,7 @@ fn test_http_get_from_vlang_utc_now() { urls := ['http://vlang.io/utc_now', 'https://vlang.io/utc_now'] for url in urls { println('Test getting current time from $url by http.get') - res := http.get(url) or { - panic(err) - } + res := http.get(url) or { panic(err) } assert 200 == res.status_code assert res.text.len > 0 assert res.text.int() > 1566403696 @@ -39,9 +37,7 @@ fn test_public_servers() { ] for url in urls { println('Testing http.get on public url: $url ') - res := http.get(url) or { - panic(err) - } + res := http.get(url) or { panic(err) } assert 200 == res.status_code assert res.text.len > 0 } @@ -53,9 +49,7 @@ fn test_relative_redirects() { } $else { return } // tempfix periodic: httpbin relative redirects are broken - res := http.get('https://httpbin.org/relative-redirect/3?abc=xyz') or { - panic(err) - } + res := http.get('https://httpbin.org/relative-redirect/3?abc=xyz') or { panic(err) } assert 200 == res.status_code assert res.text.len > 0 assert res.text.contains('"abc": "xyz"') diff --git a/vlib/net/http/response.v b/vlib/net/http/response.v index 06237668fa..7a021e077f 100644 --- a/vlib/net/http/response.v +++ b/vlib/net/http/response.v @@ -3,7 +3,7 @@ // that can be found in the LICENSE file. module http -import chunked +import net.http.chunked // Response represents the result of the request pub struct Response { @@ -23,9 +23,9 @@ fn (mut resp Response) free() { pub fn (resp Response) bytes() []byte { // TODO: build []byte directly; this uses two allocations // TODO: cookies - return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' + - '${resp.header.render(version: resp.version)}\r\n' + - '$resp.text').bytes() + return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' + '${resp.header.render( + version: resp.version + )}\r\n' + '$resp.text').bytes() } // 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) 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) } return Response{ diff --git a/vlib/net/http/status.v b/vlib/net/http/status.v index cdbf946a15..f4bc9ee5f9 100644 --- a/vlib/net/http/status.v +++ b/vlib/net/http/status.v @@ -3,7 +3,7 @@ // that can be found in the LICENSE file. module http -// The status codes listed here are based on the comprehensive list, +// The status codes listed here are based on the comprehensive list, // available at: // https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml pub enum Status { @@ -228,7 +228,9 @@ pub fn (code Status) str() string { // int converts an assigned and known Status to its integral equivalent. // if a Status is unknown or unassigned, this method will return zero pub fn (code Status) int() int { - if code in [.unknown, .unassigned] { return 0 } + if code in [.unknown, .unassigned] { + return 0 + } return int(code) } @@ -238,14 +240,14 @@ pub fn (code Status) is_valid() bool { return number >= 100 && number < 600 } -// is_error will return true if the status code represents either a client or +// is_error will return true if the status code represents either a client or // a server error; otherwise will return false pub fn (code Status) is_error() bool { number := code.int() return number >= 400 && number < 600 } -// is_success will return true if the status code represents either an +// is_success will return true if the status code represents either an // informational, success, or redirection response; otherwise will return false pub fn (code Status) is_success() bool { number := code.int()