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
|
// 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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue