diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 35ec0eea6c..3133298e53 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1224,6 +1224,21 @@ pub fn (s string) all_after(dot string) string { pub fn (s string) after(dot string) string { return s.all_after(dot) } +pub fn (s string) after_char(dot byte) string { + mut pos := 0 + for i, c in s { + if c == dot { + pos = i + break + } + } + if pos == 0 { + return s + } + return s.right(pos+1) + +} + // fn (s []string) substr(a, b int) string { // return join_strings(s.slice_fast(a, b)) // } diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index ec4eca568d..e7a66e5fc2 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -463,6 +463,9 @@ fn test_all_after() { assert s.all_after('fn ') == 'hello' assert s.all_after('test') == s assert s.all_after('') == s + assert s.after('e') == 'llo' + x := s.after('e') + assert x == 'llo' } fn test_reverse() { diff --git a/vlib/json/json_test.v b/vlib/json/json_test.v index 42d0251ad2..74424f8f1b 100644 --- a/vlib/json/json_test.v +++ b/vlib/json/json_test.v @@ -26,7 +26,7 @@ struct User { nums []int last_name string [json:lastName] is_registered bool [json:IsRegistered] - typ int [json:'type'] + typ int [json:'type'] pets string [raw; json:'pet_animals'] } @@ -47,7 +47,7 @@ fn test_parse_user() { assert u.nums[0] == 1 assert u.nums[1] == 2 assert u.nums[2] == 3 - assert u.typ == 1 + assert u.typ == 1 assert u.pets == '{"name":"Bob","animal":"Dog"}' } @@ -73,3 +73,25 @@ fn test_raw_json_field() { assert color.space == 'YCbCr' } +struct City { + name string +} + +struct Country { + cities []City + name string +} + +fn test_struct_in_struct() { + country := json.decode(Country, '{ "name": "UK", "cities": [{"name":"London"}, {"name":"Manchester"}]}') or { + assert false + exit(1) + } + assert country.name == 'UK' + assert country.cities.len == 2 + assert country.cities[0].name == 'London' + assert country.cities[1].name == 'Manchester' + println(country.cities) + +} + diff --git a/vlib/net/http/backend_nix.c.v b/vlib/net/http/backend_nix.c.v index 259aa826f5..aeb0ddc674 100644 --- a/vlib/net/http/backend_nix.c.v +++ b/vlib/net/http/backend_nix.c.v @@ -69,7 +69,7 @@ fn C.SSL_set_tlsext_host_name() int fn C.BIO_puts() -fn C.BIO_read() +fn C.BIO_read() int fn C.BIO_free_all() @@ -83,6 +83,10 @@ fn init() int { return 1 } +const ( +buf_size = 500 // 1536 +) + fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response { // ssl_method := C.SSLv23_method() ssl_method := C.TLSv1_2_method() @@ -111,6 +115,7 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response { preferred_ciphers := 'HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4' res = C.SSL_set_cipher_list(ssl, preferred_ciphers.str) if res != 1 { + println('http: openssl: cipher failed') } res = C.SSL_set_tlsext_host_name(ssl, host_name.str) res = C.BIO_do_connect(web) @@ -121,18 +126,44 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response { C.SSL_get_peer_certificate(ssl) res = C.SSL_get_verify_result(ssl) // ///// - s := req.build_request_headers(method, host_name, path) - C.BIO_puts(web, s.str) + req_headers := req.build_request_headers(method, host_name, path) + C.BIO_puts(web, req_headers.str) + mut headers := strings.new_builder(100) + mut h := '' + mut headers_done := false mut sb := strings.new_builder(100) + mut buff := [buf_size]byte + mut is_chunk_encoding := false for { - buff := [1536]byte - len := int(C.BIO_read(web, buff, 1536)) - if len > 0 { - sb.write(tos(buff, len)) - } - else { + len := C.BIO_read(web, buff, buf_size) + if len <= 0 { break } + mut chunk := (tos(buff, len)) + if !headers_done && chunk.contains('\r\n\r\n') { + headers_done = true + headers.write(chunk.all_before('\r\n')) + h = headers.str() + //println(h) + sb.write(chunk.after('\r\n')) + // TODO for some reason this can be missing from headers + is_chunk_encoding = true //h.contains('chunked') + //println(sb.str()) + continue + } + // TODO clean this up + if is_chunk_encoding && len > 6 && ((buff[3] == 13 && buff[4] == 10) || (buff[2] ==13 && buff[3]==10) + || (buff[4] == 13 && buff[5] == 10) ) { + chunk = chunk.after_char(10) + } + if chunk.len > 3 && chunk[chunk.len-2] == 13 && chunk[chunk.len-1] == 10 { + chunk = chunk[..chunk.len-2] + } + if headers_done { + sb.write(chunk) + } else { + headers.write(chunk) + } } if !isnil(web) { C.BIO_free_all(web) @@ -140,6 +171,8 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response { if !isnil(ctx) { C.SSL_CTX_free(ctx) } - return parse_response(sb.str()) + body:= sb.str() + println(body) + return parse_response(h +'\r\n\r\n'+ body) } diff --git a/vlib/net/http/http.v b/vlib/net/http/http.v index 5ed27c8ff6..77e692db18 100644 --- a/vlib/net/http/http.v +++ b/vlib/net/http/http.v @@ -45,11 +45,16 @@ pub: pub fn new_request(method, url_, data string) ?Request { url := if method == 'GET' { url_ + '?' + data } else { url_ } - // println('new req() method=$method url="$url" dta="$data"') + //println('new req() method=$method url="$url" dta="$data"') return Request{ method: method.to_upper() url: url data: data + /* + headers: { + 'Accept-Encoding': 'compress' + } + */ } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e2e0db8b0d..a178db7ec0 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -355,6 +355,10 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type { c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`', field.pos) } + if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_number(){ + c.error('ref', field.pos) + } + struct_init.fields[i].typ = expr_type struct_init.fields[i].expected_type = info_field.typ } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index fcf8482b00..24ed1c2a16 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2274,6 +2274,9 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { } } if !cloned { + if field.expected_type.is_ptr() && !field.typ.is_ptr() && !field.typ.is_number() { + g.write('/* autoref */&') + } g.expr_with_cast(field.expr, field.typ, field.expected_type) } g.writeln(',')