vweb: use http.Response constants instead of strings (#10730)
parent
cb14e42af8
commit
44e78a6301
|
@ -22,10 +22,15 @@ fn (mut resp Response) free() {
|
|||
// Formats resp to bytes suitable for HTTP response transmission
|
||||
pub fn (resp Response) bytes() []byte {
|
||||
// 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
|
||||
return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' + '${resp.header.render(
|
||||
version: resp.version
|
||||
)}\r\n' + '$resp.text').bytes()
|
||||
)}\r\n' + '$resp.text')
|
||||
}
|
||||
|
||||
// Parse a raw HTTP response into a Response object
|
||||
|
|
|
@ -12,15 +12,59 @@ import strings
|
|||
import time
|
||||
|
||||
pub const (
|
||||
methods_with_form = [http.Method.post, .put, .patch]
|
||||
header_server = 'Server: VWeb\r\n'
|
||||
header_connection_close = 'Connection: close\r\n'
|
||||
headers_close = '$header_server$header_connection_close\r\n'
|
||||
// TODO: use http.response structs
|
||||
http_400 = 'HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: 15\r\n${headers_close}400 Bad Request'
|
||||
http_404 = 'HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n${headers_close}404 Not Found'
|
||||
http_500 = 'HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n${headers_close}500 Internal Server Error'
|
||||
mime_types = map{
|
||||
methods_with_form = [http.Method.post, .put, .patch]
|
||||
http_400 = http.Response{
|
||||
version: .v1_1
|
||||
status_code: 400
|
||||
text: '400 Bad Request'
|
||||
header: fn () http.Header {
|
||||
mut h := http.new_header()
|
||||
h.add(.content_type, 'text/plain')
|
||||
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'
|
||||
'.gif': 'image/gif'
|
||||
'.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('\r\n')
|
||||
sb.write_string(vweb.headers_close)
|
||||
sb.write_string(headers_close().str())
|
||||
sb.write_string('\r\n')
|
||||
if ctx.chunked_transfer {
|
||||
mut i := 0
|
||||
mut len := res.len
|
||||
|
@ -181,7 +226,7 @@ pub fn (mut ctx Context) server_error(ecode int) Result {
|
|||
if ctx.done {
|
||||
return Result{}
|
||||
}
|
||||
send_string(mut ctx.conn, vweb.http_500) or {}
|
||||
send_string(mut ctx.conn, vweb.http_500.bytestr()) or {}
|
||||
return Result{}
|
||||
}
|
||||
|
||||
|
@ -191,7 +236,7 @@ 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$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{}
|
||||
|
@ -203,7 +248,7 @@ pub fn (mut ctx Context) not_found() Result {
|
|||
return Result{}
|
||||
}
|
||||
ctx.done = true
|
||||
send_string(mut ctx.conn, vweb.http_404) or {}
|
||||
send_string(mut ctx.conn, vweb.http_404.bytestr()) or {}
|
||||
return Result{}
|
||||
}
|
||||
|
||||
|
@ -378,7 +423,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app 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 {}
|
||||
send_string(mut conn, vweb.http_400.bytestr()) or {}
|
||||
return
|
||||
}
|
||||
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
|
||||
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 {
|
||||
|
@ -553,7 +598,7 @@ fn serve_if_static<T>(mut app T, url urllib.URL) bool {
|
|||
return false
|
||||
}
|
||||
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
|
||||
}
|
||||
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) ? {
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue