vweb: split and parse Content-Type header correctly (#9756)
parent
b11b744630
commit
e2be3ec396
|
@ -147,6 +147,7 @@ fn lines_to_string(len int, lines []string, start int, end int) string {
|
||||||
for i in start .. end {
|
for i in start .. end {
|
||||||
sb.writeln(lines[i])
|
sb.writeln(lines[i])
|
||||||
}
|
}
|
||||||
|
sb.cut_last(1) // last newline
|
||||||
res := sb.str()
|
res := sb.str()
|
||||||
unsafe { sb.free() }
|
unsafe { sb.free() }
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -112,17 +112,16 @@ ${contents[1]}
|
||||||
--------------------------$boundary--
|
--------------------------$boundary--
|
||||||
'
|
'
|
||||||
form, files := parse_multipart_form(data, boundary)
|
form, files := parse_multipart_form(data, boundary)
|
||||||
// TODO: remove newlines
|
|
||||||
assert files == map{
|
assert files == map{
|
||||||
names[0]: [FileData{
|
names[0]: [FileData{
|
||||||
filename: file
|
filename: file
|
||||||
content_type: ct
|
content_type: ct
|
||||||
data: contents[0] + '\n'
|
data: contents[0]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert form == map{
|
assert form == map{
|
||||||
names[1]: contents[1] + '\n'
|
names[1]: contents[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,31 @@ fn test_http_client_json_post() ? {
|
||||||
assert '$ouser' == '$nuser2'
|
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() {
|
fn test_http_client_shutdown_does_not_work_without_a_cookie() {
|
||||||
x := http.get('http://127.0.0.1:$sport/shutdown') or {
|
x := http.get('http://127.0.0.1:$sport/shutdown') or {
|
||||||
assert err.msg == ''
|
assert err.msg == ''
|
||||||
|
|
|
@ -85,6 +85,12 @@ pub fn (mut app App) json_echo() vweb.Result {
|
||||||
return app.ok(app.req.data)
|
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
|
// Make sure [post] works without the path
|
||||||
[post]
|
[post]
|
||||||
pub fn (mut app App) json() vweb.Result {
|
pub fn (mut app App) json() vweb.Result {
|
||||||
|
|
|
@ -336,8 +336,9 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
||||||
page_gen_start: page_gen_start
|
page_gen_start: page_gen_start
|
||||||
}
|
}
|
||||||
if req.method in vweb.methods_with_form {
|
if req.method in vweb.methods_with_form {
|
||||||
if 'multipart/form-data' in req.header.values(.content_type) {
|
ct := req.header.get(.content_type) or { '' }.split(';').map(it.trim_left(' \t'))
|
||||||
boundary := req.header.values(.content_type).filter(it.starts_with('boundary='))
|
if 'multipart/form-data' in ct {
|
||||||
|
boundary := ct.filter(it.starts_with('boundary='))
|
||||||
if boundary.len != 1 {
|
if boundary.len != 1 {
|
||||||
send_string(mut conn, vweb.http_400) or {}
|
send_string(mut conn, vweb.http_400) or {}
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue