forked from vieter-v/vieter
				
			feat(web): file() now handles HEAD requests
							parent
							
								
									3a73ea0632
								
							
						
					
					
						commit
						e7b45bf251
					
				|  | @ -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) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<T>(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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue