vweb: use http.Response constants instead of strings (#10730)

pull/10746/head
Miccah 2021-07-10 03:58:07 -05:00 committed by GitHub
parent cb14e42af8
commit 44e78a6301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 17 deletions

View File

@ -22,10 +22,15 @@ fn (mut resp Response) free() {
// Formats resp to bytes suitable for HTTP response transmission // Formats resp to bytes suitable for HTTP response transmission
pub fn (resp Response) bytes() []byte { pub fn (resp Response) bytes() []byte {
// TODO: build []byte directly; this uses two allocations // TODO: build []byte directly; this uses two allocations
return resp.bytestr().bytes()
}
// Formats resp to a string suitable for HTTP response transmission
pub fn (resp Response) bytestr() string {
// TODO: cookies // TODO: cookies
return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' + '${resp.header.render( return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' + '${resp.header.render(
version: resp.version version: resp.version
)}\r\n' + '$resp.text').bytes() )}\r\n' + '$resp.text')
} }
// Parse a raw HTTP response into a Response object // Parse a raw HTTP response into a Response object

View File

@ -12,15 +12,59 @@ import strings
import time import time
pub const ( pub const (
methods_with_form = [http.Method.post, .put, .patch] methods_with_form = [http.Method.post, .put, .patch]
header_server = 'Server: VWeb\r\n' http_400 = http.Response{
header_connection_close = 'Connection: close\r\n' version: .v1_1
headers_close = '$header_server$header_connection_close\r\n' status_code: 400
// TODO: use http.response structs text: '400 Bad Request'
http_400 = 'HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: 15\r\n${headers_close}400 Bad Request' header: fn () http.Header {
http_404 = 'HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n${headers_close}404 Not Found' mut h := http.new_header()
http_500 = 'HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n${headers_close}500 Internal Server Error' h.add(.content_type, 'text/plain')
mime_types = map{ h.add(.content_length, '15')
close := headers_close()
for k in close.keys() {
for v in close.custom_values(k) {
h.add_custom(k, v) or {}
}
}
return h
}()
}
http_404 = http.Response{
version: .v1_1
status_code: 404
text: '404 Not Found'
header: fn () http.Header {
mut h := http.new_header()
h.add(.content_type, 'text/plain')
h.add(.content_length, '13')
close := headers_close()
for k in close.keys() {
for v in close.custom_values(k) {
h.add_custom(k, v) or {}
}
}
return h
}()
}
http_500 = http.Response{
version: .v1_1
status_code: 500
text: '500 Internal Server Error'
header: fn () http.Header {
mut h := http.new_header()
h.add(.content_type, 'text/plain')
h.add(.content_length, '25')
close := headers_close()
for k in close.keys() {
for v in close.custom_values(k) {
h.add_custom(k, v) or {}
}
}
return h
}()
}
mime_types = map{
'.css': 'text/css; charset=utf-8' '.css': 'text/css; charset=utf-8'
'.gif': 'image/gif' '.gif': 'image/gif'
'.htm': 'text/html; charset=utf-8' '.htm': 'text/html; charset=utf-8'
@ -117,7 +161,8 @@ pub fn (mut ctx Context) send_response_to_client(mimetype string, res string) bo
} }
sb.write_string(ctx.headers) sb.write_string(ctx.headers)
sb.write_string('\r\n') sb.write_string('\r\n')
sb.write_string(vweb.headers_close) sb.write_string(headers_close().str())
sb.write_string('\r\n')
if ctx.chunked_transfer { if ctx.chunked_transfer {
mut i := 0 mut i := 0
mut len := res.len mut len := res.len
@ -181,7 +226,7 @@ pub fn (mut ctx Context) server_error(ecode int) Result {
if ctx.done { if ctx.done {
return Result{} return Result{}
} }
send_string(mut ctx.conn, vweb.http_500) or {} send_string(mut ctx.conn, vweb.http_500.bytestr()) or {}
return Result{} return Result{}
} }
@ -191,7 +236,7 @@ pub fn (mut ctx Context) redirect(url string) Result {
return Result{} return Result{}
} }
ctx.done = true ctx.done = true
send_string(mut ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: $url$ctx.headers\r\n$vweb.headers_close') or { send_string(mut ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: $url$ctx.headers\r\n$headers_close().str()\r\n') or {
return Result{} return Result{}
} }
return Result{} return Result{}
@ -203,7 +248,7 @@ pub fn (mut ctx Context) not_found() Result {
return Result{} return Result{}
} }
ctx.done = true ctx.done = true
send_string(mut ctx.conn, vweb.http_404) or {} send_string(mut ctx.conn, vweb.http_404.bytestr()) or {}
return Result{} return Result{}
} }
@ -378,7 +423,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
if 'multipart/form-data' in ct { if 'multipart/form-data' in ct {
boundary := ct.filter(it.starts_with('boundary=')) 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.bytestr()) or {}
return return
} }
form, files := parse_multipart_form(req.data, boundary[0][9..]) form, files := parse_multipart_form(req.data, boundary[0][9..])
@ -457,7 +502,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
} }
} }
// site not found // site not found
send_string(mut conn, vweb.http_404) or {} send_string(mut conn, vweb.http_404.bytestr()) or {}
} }
fn route_matches(url_words []string, route_words []string) ?[]string { fn route_matches(url_words []string, route_words []string) ?[]string {
@ -553,7 +598,7 @@ fn serve_if_static<T>(mut app T, url urllib.URL) bool {
return false return false
} }
data := os.read_file(static_file) or { data := os.read_file(static_file) or {
send_string(mut app.conn, vweb.http_404) or {} send_string(mut app.conn, vweb.http_404.bytestr()) or {}
return true return true
} }
app.send_response_to_client(mime_type, data) app.send_response_to_client(mime_type, data)
@ -662,3 +707,9 @@ pub type RawHtml = string
fn send_string(mut conn net.TcpConn, s string) ? { fn send_string(mut conn net.TcpConn, s string) ? {
conn.write(s.bytes()) ? conn.write(s.bytes()) ?
} }
fn headers_close() http.Header {
mut h := http.new_header(key: .connection, value: 'close')
h.add_custom('Server', 'VWeb') or {}
return h
}