mirror of
				https://gitea.invidious.io/iv-org/shard-kemal.git
				synced 2024-08-15 00:53:36 +00:00 
			
		
		
		
	Add allocation optimizations (#487)
This commit is contained in:
		
							parent
							
								
									afd17fc774
								
							
						
					
					
						commit
						21ab64511a
					
				
					 12 changed files with 59 additions and 82 deletions
				
			
		
							
								
								
									
										13
									
								
								src/kemal.cr
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								src/kemal.cr
									
										
									
									
									
								
							|  | @ -68,15 +68,12 @@ module Kemal | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def self.stop |   def self.stop | ||||||
|     if config.running |     raise "Kemal is already stopped." if !config.running | ||||||
|       if server = config.server |     if server = config.server | ||||||
|         server.close unless server.closed? |       server.close unless server.closed? | ||||||
|         config.running = false |       config.running = false | ||||||
|       else |  | ||||||
|         raise "Kemal.config.server is not set. Please use Kemal.run to set the server." |  | ||||||
|       end |  | ||||||
|     else |     else | ||||||
|       raise "Kemal is already stopped." |       raise "Kemal.config.server is not set. Please use Kemal.run to set the server." | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -41,14 +41,8 @@ module Kemal | ||||||
|     private def configure_ssl |     private def configure_ssl | ||||||
|       {% if !flag?(:without_openssl) %} |       {% if !flag?(:without_openssl) %} | ||||||
|       if @ssl_enabled |       if @ssl_enabled | ||||||
|         unless @key_file |         abort "SSL Key Not Found" if !@key_file | ||||||
|           puts "SSL Key Not Found" |         abort "SSL Certificate Not Found" if !@cert_file | ||||||
|           exit |  | ||||||
|         end |  | ||||||
|         unless @cert_file |  | ||||||
|           puts "SSL Certificate Not Found" |  | ||||||
|           exit |  | ||||||
|         end |  | ||||||
|         ssl = Kemal::SSL.new |         ssl = Kemal::SSL.new | ||||||
|         ssl.key_file = @key_file.not_nil! |         ssl.key_file = @key_file.not_nil! | ||||||
|         ssl.cert_file =  @cert_file.not_nil! |         ssl.cert_file =  @cert_file.not_nil! | ||||||
|  | @ -58,7 +52,9 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def read_env |     private def read_env | ||||||
|       @config.env = ENV["KEMAL_ENV"] if ENV.has_key?("KEMAL_ENV") |       if kemal_env = ENV["KEMAL_ENV"]? | ||||||
|  |         @config.env = kemal_env | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -144,15 +144,10 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def setup_custom_handlers |     private def setup_custom_handlers | ||||||
|       CUSTOM_HANDLERS.each do |ch| |       CUSTOM_HANDLERS.each do |ch0, ch1| | ||||||
|         position = ch[0] |         position = ch0 | ||||||
|         if !position |         HANDLERS.insert (position || @handler_position), ch1 | ||||||
|           HANDLERS.insert(@handler_position, ch[1]) |         @handler_position += 1 | ||||||
|           @handler_position += 1 |  | ||||||
|         else |  | ||||||
|           HANDLERS.insert(position, ch[1]) |  | ||||||
|           @handler_position += 1 |  | ||||||
|         end |  | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ module Kemal | ||||||
|     def _add_route_filter(verb : String, path, type, &block : HTTP::Server::Context -> _) |     def _add_route_filter(verb : String, path, type, &block : HTTP::Server::Context -> _) | ||||||
|       lookup = lookup_filters_for_path_type(verb, path, type) |       lookup = lookup_filters_for_path_type(verb, path, type) | ||||||
|       if lookup.found? && lookup.payload.is_a?(Array(FilterBlock)) |       if lookup.found? && lookup.payload.is_a?(Array(FilterBlock)) | ||||||
|         (lookup.payload.as(Array(FilterBlock))) << FilterBlock.new(&block) |         lookup.payload << FilterBlock.new(&block) | ||||||
|       else |       else | ||||||
|         @tree.add radix_path(verb, path, type), [FilterBlock.new(&block)] |         @tree.add radix_path(verb, path, type), [FilterBlock.new(&block)] | ||||||
|       end |       end | ||||||
|  | @ -54,8 +54,8 @@ module Kemal | ||||||
|     private def call_block_for_path_type(verb : String?, path : String, type, context : HTTP::Server::Context) |     private def call_block_for_path_type(verb : String?, path : String, type, context : HTTP::Server::Context) | ||||||
|       lookup = lookup_filters_for_path_type(verb, path, type) |       lookup = lookup_filters_for_path_type(verb, path, type) | ||||||
|       if lookup.found? && lookup.payload.is_a? Array(FilterBlock) |       if lookup.found? && lookup.payload.is_a? Array(FilterBlock) | ||||||
|         blocks = lookup.payload.as(Array(FilterBlock)) |         blocks = lookup.payload | ||||||
|         blocks.each { |block| block.call(context) } |         blocks.each &.call(context) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,15 +11,17 @@ module Kemal | ||||||
| 
 | 
 | ||||||
|     macro only(paths, method = "GET") |     macro only(paths, method = "GET") | ||||||
|       class_name = {{@type.name}} |       class_name = {{@type.name}} | ||||||
|  |       method_downcase = {{method}}.downcase | ||||||
|  |       class_name_method = "#{class_name}/#{method_downcase}" | ||||||
|       ({{paths}}).each do |path| |       ({{paths}}).each do |path| | ||||||
|         @@only_routes_tree.add "#{class_name}/#{{{method}}.downcase}#{path}", "/#{{{method}}.downcase}#{path}" |         @@only_routes_tree.add class_name_method + path, '/' + method_downcase + path | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     macro exclude(paths, method = "GET") |     macro exclude(paths, method = "GET") | ||||||
|       class_name = {{@type.name}} |       class_name = {{@type.name}} | ||||||
|       ({{paths}}).each do |path| |       ({{paths}}).each do |path| | ||||||
|         @@exclude_routes_tree.add "#{class_name}/#{{{method}}.downcase}#{path}", "/#{{{method}}.downcase}#{path}" |         @@exclude_routes_tree.add class_name_method + path, '/' + method_downcase + path | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -127,12 +127,14 @@ def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = | ||||||
|     if env.request.method == "GET" && env.request.headers.has_key?("Range") |     if env.request.method == "GET" && env.request.headers.has_key?("Range") | ||||||
|       next multipart(file, env) |       next multipart(file, env) | ||||||
|     end |     end | ||||||
|     if request_headers.includes_word?("Accept-Encoding", "gzip") && config.is_a?(Hash) && config["gzip"] == true && filesize > minsize && Kemal::Utils.zip_types(file_path) | 
 | ||||||
|  |     condition = config.is_a?(Hash) && config["gzip"]? == true && filesize > minsize && Kemal::Utils.zip_types(file_path) | ||||||
|  |     if condition && request_headers.includes_word?("Accept-Encoding", "gzip") | ||||||
|       env.response.headers["Content-Encoding"] = "gzip" |       env.response.headers["Content-Encoding"] = "gzip" | ||||||
|       Gzip::Writer.open(env.response) do |deflate| |       Gzip::Writer.open(env.response) do |deflate| | ||||||
|         IO.copy(file, deflate) |         IO.copy(file, deflate) | ||||||
|       end |       end | ||||||
|     elsif request_headers.includes_word?("Accept-Encoding", "deflate") && config.is_a?(Hash) && config["gzip"]? == true && filesize > minsize && Kemal::Utils.zip_types(file_path) |     elsif condition && request_headers.includes_word?("Accept-Encoding", "deflate") | ||||||
|       env.response.headers["Content-Encoding"] = "deflate" |       env.response.headers["Content-Encoding"] = "deflate" | ||||||
|       Flate::Writer.open(env.response) do |deflate| |       Flate::Writer.open(env.response) do |deflate| | ||||||
|         IO.copy(file, deflate) |         IO.copy(file, deflate) | ||||||
|  | @ -148,28 +150,16 @@ end | ||||||
| private def multipart(file, env : HTTP::Server::Context) | private def multipart(file, env : HTTP::Server::Context) | ||||||
|   # See http://httpwg.org/specs/rfc7233.html |   # See http://httpwg.org/specs/rfc7233.html | ||||||
|   fileb = file.size |   fileb = file.size | ||||||
|  |   startb = endb = 0 | ||||||
| 
 | 
 | ||||||
|   range = env.request.headers["Range"] |   if match = env.request.headers["Range"].match /bytes=(\d{1,})-(\d{0,})/ | ||||||
|   match = range.match(/bytes=(\d{1,})-(\d{0,})/) |     startb = match[1].to_i { 0 } if match.size >= 2 | ||||||
| 
 |     endb = match[2].to_i { 0 } if match.size >= 3 | ||||||
|   startb = 0 |  | ||||||
|   endb = 0 |  | ||||||
| 
 |  | ||||||
|   if match |  | ||||||
|     if match.size >= 2 |  | ||||||
|       startb = match[1].to_i { 0 } |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     if match.size >= 3 |  | ||||||
|       endb = match[2].to_i { 0 } |  | ||||||
|     end |  | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   if endb == 0 |   endb = fileb - 1 if endb == 0 | ||||||
|     endb = fileb - 1 |  | ||||||
|   end |  | ||||||
| 
 | 
 | ||||||
|   if startb < endb && endb < fileb |   if startb < endb < fileb | ||||||
|     content_length = 1 + endb - startb |     content_length = 1 + endb - startb | ||||||
|     env.response.status_code = 206 |     env.response.status_code = 206 | ||||||
|     env.response.content_length = content_length |     env.response.content_length = content_length | ||||||
|  | @ -179,12 +169,12 @@ private def multipart(file, env : HTTP::Server::Context) | ||||||
|     if startb > 1024 |     if startb > 1024 | ||||||
|       skipped = 0 |       skipped = 0 | ||||||
|       # file.skip only accepts values less or equal to 1024 (buffer size, undocumented) |       # file.skip only accepts values less or equal to 1024 (buffer size, undocumented) | ||||||
|       until skipped + 1024 > startb |       until (increase_skipped = skipped + 1024) > startb | ||||||
|         file.skip(1024) |         file.skip(1024) | ||||||
|         skipped += 1024 |         skipped = increase_skipped | ||||||
|       end |       end | ||||||
|       if skipped - startb > 0 |       if (skipped_minus_startb = skipped - startb) > 0 | ||||||
|         file.skip(skipped - startb) |         file.skip skipped_minus_startb | ||||||
|       end |       end | ||||||
|     else |     else | ||||||
|       file.skip(startb) |       file.skip(startb) | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| module Kemal | module Kemal | ||||||
|   module Utils |   module Utils | ||||||
|     ZIP_TYPES = [".htm", ".html", ".txt", ".css", ".js", ".svg", ".json", ".xml", ".otf", ".ttf", ".woff", ".woff2"] |     ZIP_TYPES = {".htm", ".html", ".txt", ".css", ".js", ".svg", ".json", ".xml", ".otf", ".ttf", ".woff", ".woff2"} | ||||||
| 
 | 
 | ||||||
|     def self.path_starts_with_slash?(path : String) |     def self.path_starts_with_slash?(path : String) | ||||||
|       path.starts_with?("/") |       path.starts_with? '/' | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def self.zip_types(path : String) # https://github.com/h5bp/server-configs-nginx/blob/master/nginx.conf |     def self.zip_types(path : String) # https://github.com/h5bp/server-configs-nginx/blob/master/nginx.conf | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ module Kemal | ||||||
|       time = Time.now |       time = Time.now | ||||||
|       call_next(context) |       call_next(context) | ||||||
|       elapsed_text = elapsed_text(Time.now - time) |       elapsed_text = elapsed_text(Time.now - time) | ||||||
|       @io << time << " " << context.response.status_code << " " << context.request.method << " " << context.request.resource << " " << elapsed_text << "\n" |       @io << time << ' ' << context.response.status_code << ' ' << context.request.method << ' ' << context.request.resource << ' ' << elapsed_text << '\n' | ||||||
|       context |       context | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def unescape_url_param(value : String) |     private def unescape_url_param(value : String) | ||||||
|       value.size == 0 ? value : URI.unescape(value) |       value.empty? ? value : URI.unescape(value) | ||||||
|     rescue |     rescue | ||||||
|       value |       value | ||||||
|     end |     end | ||||||
|  | @ -74,19 +74,11 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def parse_part(part : IO?) |     private def parse_part(part : IO?) | ||||||
|       if part |       HTTP::Params.parse(part ? part.gets_to_end : "") | ||||||
|         HTTP::Params.parse(part.gets_to_end) |  | ||||||
|       else |  | ||||||
|         HTTP::Params.parse("") |  | ||||||
|       end |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def parse_part(part : String?) |     private def parse_part(part : String?) | ||||||
|       if part |       HTTP::Params.parse part.to_s | ||||||
|         HTTP::Params.parse(part.to_s) |  | ||||||
|       else |  | ||||||
|         HTTP::Params.parse("") |  | ||||||
|       end |  | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -56,7 +56,7 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def radix_path(method, path) |     private def radix_path(method, path) | ||||||
|       "/#{method.downcase}#{path}" |       '/' + method.downcase + path | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def add_to_radix_tree(method, path, route) |     private def add_to_radix_tree(method, path, route) | ||||||
|  |  | ||||||
|  | @ -7,7 +7,9 @@ module Kemal | ||||||
|     def call(context : HTTP::Server::Context) |     def call(context : HTTP::Server::Context) | ||||||
|       return call_next(context) if context.request.path.not_nil! == "/" |       return call_next(context) if context.request.path.not_nil! == "/" | ||||||
| 
 | 
 | ||||||
|       unless context.request.method == "GET" || context.request.method == "HEAD" |       case context.request.method | ||||||
|  |       when "GET", "HEAD" | ||||||
|  |       else | ||||||
|         if @fallthrough |         if @fallthrough | ||||||
|           call_next(context) |           call_next(context) | ||||||
|         else |         else | ||||||
|  | @ -19,7 +21,6 @@ module Kemal | ||||||
| 
 | 
 | ||||||
|       config = Kemal.config.serve_static |       config = Kemal.config.serve_static | ||||||
|       original_path = context.request.path.not_nil! |       original_path = context.request.path.not_nil! | ||||||
|       is_dir_path = original_path.ends_with? "/" |  | ||||||
|       request_path = URI.unescape(original_path) |       request_path = URI.unescape(original_path) | ||||||
| 
 | 
 | ||||||
|       # File path cannot contains '\0' (NUL) because all filesystem I know |       # File path cannot contains '\0' (NUL) because all filesystem I know | ||||||
|  | @ -30,16 +31,20 @@ module Kemal | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       expanded_path = File.expand_path(request_path, "/") |       expanded_path = File.expand_path(request_path, "/") | ||||||
|       if is_dir_path && !expanded_path.ends_with? "/" |       is_dir_path = if original_path.ends_with?('/') && !expanded_path.ends_with? '/' | ||||||
|         expanded_path = "#{expanded_path}/" |                       expanded_path = expanded_path + '/' | ||||||
|       end |                       true | ||||||
|       is_dir_path = expanded_path.ends_with? "/" |                     else | ||||||
|  |                       expanded_path.ends_with? '/' | ||||||
|  |                     end | ||||||
| 
 | 
 | ||||||
|       file_path = File.join(@public_dir, expanded_path) |       file_path = File.join(@public_dir, expanded_path) | ||||||
|       is_dir = Dir.exists? file_path |       is_dir = Dir.exists? file_path | ||||||
| 
 | 
 | ||||||
|       if request_path != expanded_path || is_dir && !is_dir_path |       if request_path != expanded_path | ||||||
|         redirect_to context, "#{expanded_path}#{is_dir && !is_dir_path ? "/" : ""}" |         redirect_to context, expanded_path | ||||||
|  |       elsif is_dir && !is_dir_path | ||||||
|  |         redirect_to context, expanded_path + '/' | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       if Dir.exists?(file_path) |       if Dir.exists?(file_path) | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def lookup_ws_route(path : String) |     def lookup_ws_route(path : String) | ||||||
|       @routes.find "/ws#{path}" |       @routes.find "/ws" + path | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def add_route(path : String, &handler : HTTP::WebSocket, HTTP::Server::Context -> Void) |     def add_route(path : String, &handler : HTTP::WebSocket, HTTP::Server::Context -> Void) | ||||||
|  | @ -30,12 +30,12 @@ module Kemal | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def radix_path(method, path) |     private def radix_path(method, path) | ||||||
|       "/#{method.downcase}#{path}" |       '/' + method.downcase + path | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def websocket_upgrade_request?(context) |     private def websocket_upgrade_request?(context) | ||||||
|       return false unless upgrade = context.request.headers["Upgrade"]? |       return unless upgrade = context.request.headers["Upgrade"]? | ||||||
|       return false unless upgrade.compare("websocket", case_insensitive: true) == 0 |       return unless upgrade.compare("websocket", case_insensitive: true) == 0 | ||||||
| 
 | 
 | ||||||
|       context.request.headers.includes_word?("Connection", "Upgrade") |       context.request.headers.includes_word?("Connection", "Upgrade") | ||||||
|     end |     end | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue