diff --git a/cmd/tools/vtest-self.v b/cmd/tools/vtest-self.v index 3e60de0c4f..9ad42bcd05 100644 --- a/cmd/tools/vtest-self.v +++ b/cmd/tools/vtest-self.v @@ -47,6 +47,7 @@ const ( 'vlib/vweb/tests/vweb_test.v', 'vlib/vweb/request_test.v', 'vlib/net/http/request_test.v', + 'vlib/net/http/response_test.v', 'vlib/vweb/route_test.v', 'vlib/net/websocket/websocket_test.v', 'vlib/crypto/rand/crypto_rand_read_test.v', @@ -89,6 +90,7 @@ const ( 'vlib/net/http/http_httpbin_test.v', 'vlib/net/http/header_test.v', 'vlib/net/http/server_test.v', + 'vlib/net/http/response_test.v', ] skip_on_linux = [ 'do_not_remove', diff --git a/vlib/net/http/response_test.v b/vlib/net/http/response_test.v new file mode 100644 index 0000000000..bf2fba3f6a --- /dev/null +++ b/vlib/net/http/response_test.v @@ -0,0 +1,36 @@ +module http + +fn test_response_bytestr() ? { + { + resp := new_response( + status: .ok + text: 'Foo' + ) + assert resp.bytestr() == 'HTTP/1.1 200 OK\r\n' + 'Content-Length: 3\r\n' + '\r\n' + 'Foo' + } + { + resp := new_response( + status: .found + text: 'Foo' + header: new_header(key: .location, value: '/') + ) + lines := resp.bytestr().split_into_lines() + assert lines[0] == 'HTTP/1.1 302 Found' + // header order is not guaranteed + check_headers(['Location: /', 'Content-Length: 3'], lines[1..3]) ? + assert lines[3] == '' + assert lines[4] == 'Foo' + } +} + +// check_headers is a helper function for asserting all expected headers +// are found because rendered header order is not guaranteed. The check +// is O(n^2) which is fine for small lists. +fn check_headers(expected []string, found []string) ? { + assert expected.len == found.len + for header in expected { + if !found.contains(header) { + return error('expected header "$header" not in $found') + } + } +} diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 6361b627fa..38c8d9c821 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -17,6 +17,11 @@ pub const ( http.CommonHeader.connection.str(): 'close' }) or { panic('should never fail') } + http_302 = http.new_response( + status: .found + text: '302 Found' + header: headers_close + ) http_400 = http.new_response( status: .bad_request text: '400 Bad Request' @@ -246,9 +251,10 @@ pub fn (mut ctx Context) redirect(url string) Result { return Result{} } ctx.done = true - send_string(mut ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: $url\r\n$ctx.header\r\n$vweb.headers_close\r\n') or { - return Result{} - } + mut resp := vweb.http_302 + resp.header = resp.header.join(ctx.header) + resp.header.add(.location, url) + send_string(mut ctx.conn, resp.bytestr()) or { return Result{} } return Result{} }