diff --git a/vlib/vweb/request.v b/vlib/vweb/request.v index a42d5ccc61..faa56a995c 100644 --- a/vlib/vweb/request.v +++ b/vlib/vweb/request.v @@ -147,6 +147,7 @@ fn lines_to_string(len int, lines []string, start int, end int) string { for i in start .. end { sb.writeln(lines[i]) } + sb.cut_last(1) // last newline res := sb.str() unsafe { sb.free() } return res diff --git a/vlib/vweb/request_test.v b/vlib/vweb/request_test.v index 10301e9cfe..ad6d960a72 100644 --- a/vlib/vweb/request_test.v +++ b/vlib/vweb/request_test.v @@ -112,17 +112,16 @@ ${contents[1]} --------------------------$boundary-- ' form, files := parse_multipart_form(data, boundary) - // TODO: remove newlines assert files == map{ names[0]: [FileData{ filename: file content_type: ct - data: contents[0] + '\n' + data: contents[0] }] } assert form == map{ - names[1]: contents[1] + '\n' + names[1]: contents[1] } } diff --git a/vlib/vweb/tests/vweb_test.v b/vlib/vweb/tests/vweb_test.v index 124a906f0b..8951c33adc 100644 --- a/vlib/vweb/tests/vweb_test.v +++ b/vlib/vweb/tests/vweb_test.v @@ -208,6 +208,31 @@ fn test_http_client_json_post() ? { assert '$ouser' == '$nuser2' } +fn test_http_client_multipart_form_data() ? { + boundary := '6844a625b1f0b299' + name := 'foo' + ct := 'multipart/form-data; boundary=------------------------$boundary' + contents := 'baz buzz' + data := '--------------------------$boundary +Content-Disposition: form-data; name=\"$name\" + +$contents +--------------------------$boundary-- +' + mut x := http.fetch('http://127.0.0.1:$sport/form_echo', + method: .post + header: http.new_header( + key: .content_type + value: ct + ) + data: data + ) ? + $if debug_net_socket_client ? { + eprintln('/form_echo endpoint response: $x') + } + assert x.text == contents +} + fn test_http_client_shutdown_does_not_work_without_a_cookie() { x := http.get('http://127.0.0.1:$sport/shutdown') or { assert err.msg == '' diff --git a/vlib/vweb/tests/vweb_test_server.v b/vlib/vweb/tests/vweb_test_server.v index 1276aacb4d..88f3cf527f 100644 --- a/vlib/vweb/tests/vweb_test_server.v +++ b/vlib/vweb/tests/vweb_test_server.v @@ -85,6 +85,12 @@ pub fn (mut app App) json_echo() vweb.Result { return app.ok(app.req.data) } +['/form_echo'; post] +pub fn (mut app App) form_echo() vweb.Result { + app.set_content_type(app.req.header.get(.content_type) or { '' }) + return app.ok(app.form['foo']) +} + // Make sure [post] works without the path [post] pub fn (mut app App) json() vweb.Result { diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 8f9fdff45c..004433ed04 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -336,8 +336,9 @@ fn handle_conn(mut conn net.TcpConn, mut app T) { page_gen_start: page_gen_start } if req.method in vweb.methods_with_form { - if 'multipart/form-data' in req.header.values(.content_type) { - boundary := req.header.values(.content_type).filter(it.starts_with('boundary=')) + ct := req.header.get(.content_type) or { '' }.split(';').map(it.trim_left(' \t')) + if 'multipart/form-data' in ct { + boundary := ct.filter(it.starts_with('boundary=')) if boundary.len != 1 { send_string(mut conn, vweb.http_400) or {} return