From e7b45bf251736cbd60fcb49aa45bd2b7012125fe Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Fri, 12 Aug 2022 15:08:05 +0200 Subject: [PATCH] feat(web): file() now handles HEAD requests --- src/server/repo.v | 9 ----- src/web/web.v | 90 +++++++++++------------------------------------ 2 files changed, 20 insertions(+), 79 deletions(-) diff --git a/src/server/repo.v b/src/server/repo.v index fbf37df..4a417fb 100644 --- a/src/server/repo.v +++ b/src/server/repo.v @@ -45,15 +45,6 @@ fn (mut app App) get_repo_file(repo string, arch string, filename string) web.Re full_path = os.join_path(app.repo.repos_dir, repo, arch, filename, 'desc') } - // Scuffed way to respond to HEAD requests - if app.req.method == http.Method.head { - if os.exists(full_path) { - return app.status(http.Status.ok) - } - - return app.not_found() - } - return app.file(full_path) } diff --git a/src/web/web.v b/src/web/web.v index 9fe0ddc..c4cfee7 100644 --- a/src/web/web.v +++ b/src/web/web.v @@ -25,10 +25,10 @@ pub mut: conn &net.TcpConn // Gives access to a shared logger object logger shared log.Log - // REQUEST // time.ticks() from start of web connection handle. // You can use it to determine how much time is spent on your request. page_gen_start i64 + // REQUEST static_files map[string]string static_mime_types map[string]string // Map containing query params for the route. @@ -103,6 +103,12 @@ pub fn (mut ctx Context) send_response_header() ? { ctx.send_string(resp.bytestr())? } +// send is a convenience function for sending the HTTP response with an empty +// body. +pub fn (mut ctx Context) send() bool { + return ctx.send_response('') +} + // send_response constructs the resulting HTTP response with the given body // string & sends it to the client. pub fn (mut ctx Context) send_response(res string) bool { @@ -144,67 +150,32 @@ pub fn (mut ctx Context) json(status http.Status, j T) Result { // file Response HTTP_OK with file as payload // This function manually implements responses because it needs to stream the file contents pub fn (mut ctx Context) file(f_path string) Result { + // If the file doesn't exist, just respond with a 404 if !os.is_file(f_path) { - return ctx.not_found() + ctx.status = .not_found + ctx.send() + + return Result{} } - // ext := os.file_ext(f_path) - // data := os.read_file(f_path) or { - // eprint(err.msg()) - // ctx.server_error(500) - // return Result{} - // } - // content_type := web.mime_types[ext] - // if content_type == '' { - // eprintln('no MIME type found for extension $ext') - // ctx.server_error(500) + file_size := os.file_size(f_path) + ctx.header.add(http.CommonHeader.content_length, file_size.str()) - // return Result{} - // } + // A HEAD request only returns the size of the file. + if ctx.req.method == .head { + ctx.send() - // First, we return the headers for the request + return Result{} + } // We open the file before sending the headers in case reading fails - file_size := os.file_size(f_path) - mut file := os.open(f_path) or { eprintln(err.msg()) ctx.server_error(500) return Result{} } - // build header - header := http.new_header_from_map({ - // http.CommonHeader.content_type: content_type - http.CommonHeader.content_length: file_size.str() - }).join(ctx.header) - - mut resp := http.Response{ - header: header.join(headers_close) - } - resp.set_version(.v1_1) - resp.set_status(ctx.status) - ctx.send_string(resp.bytestr()) or { return Result{} } - ctx.send_reader(mut file, file_size) or { return Result{} } - - // mut buf := []u8{len: 1_000_000} - // mut bytes_left := file_size - - // // Repeat as long as the stream still has data - // for bytes_left > 0 { - // // TODO check if just breaking here is safe - // bytes_read := file.read(mut buf) or { break } - // bytes_left -= u64(bytes_read) - - // mut to_write := bytes_read - - // for to_write > 0 { - // // TODO don't just loop infinitely here - // bytes_written := ctx.conn.write(buf[bytes_read - to_write..bytes_read]) or { continue } - - // to_write = to_write - bytes_written - // } - // } + ctx.send_reader_response(mut file, file_size) return Result{} } @@ -472,27 +443,6 @@ fn route_matches(url_words []string, route_words []string) ?[]string { return params } -// ip Returns the ip address from the current user -pub fn (ctx &Context) ip() string { - mut ip := ctx.req.header.get(.x_forwarded_for) or { '' } - if ip == '' { - ip = ctx.req.header.get_custom('X-Real-Ip') or { '' } - } - - if ip.contains(',') { - ip = ip.all_before(',') - } - if ip == '' { - ip = ctx.conn.peer_ip() or { '' } - } - return ip -} - -// error Set s to the form error -pub fn (mut ctx Context) error(s string) { - println('web error: $s') -} - // filter Do not delete. // It used by `vlib/v/gen/c/str_intp.v:130` for string interpolation inside web templates // TODO: move it to template render