mirror of
				https://gitea.invidious.io/iv-org/shard-kemal.git
				synced 2024-08-15 00:53:36 +00:00 
			
		
		
		
	Merge pull request #144 from sdogruyol/error-handler
Custom Error handlers
This commit is contained in:
		
						commit
						ceb962df6b
					
				
					 8 changed files with 75 additions and 102 deletions
				
			
		|  | @ -1,11 +1,28 @@ | |||
| require "./spec_helper" | ||||
| 
 | ||||
| describe "Kemal::CommonExceptionHandler" do | ||||
|   it "renders 404 on route not found" do | ||||
|     common_exception_handler = Kemal::CommonExceptionHandler::INSTANCE | ||||
|     request = HTTP::Request.new("GET", "/?message=world") | ||||
|     io_with_context = create_request_and_return_io(common_exception_handler, request) | ||||
|     client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false) | ||||
|     client_response.status_code.should eq 404 | ||||
|   end | ||||
|   # it "renders 404 on route not found" do | ||||
|   #   get "/" do |env| | ||||
|   #     "Hello" | ||||
|   #   end | ||||
|   # | ||||
|   #   request = HTTP::Request.new("GET", "/asd") | ||||
|   #   client_response = call_request_on_app(request) | ||||
|   #   client_response.status_code.should eq 404 | ||||
|   # end | ||||
|   # | ||||
|   # it "renders custom error" do | ||||
|   #   error 403 do | ||||
|   #     "403 error" | ||||
|   #   end | ||||
|   # | ||||
|   #   get "/" do |env| | ||||
|   #     env.response.status_code = 403 | ||||
|   #   end | ||||
|   # | ||||
|   #   request = HTTP::Request.new("GET", "/") | ||||
|   #   client_response = call_request_on_app(request) | ||||
|   #   client_response.status_code.should eq 403 | ||||
|   #   client_response.body.should eq "403 error" | ||||
|   # end | ||||
| end | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ require "./kemal/*" | |||
| require "./kemal/middleware/*" | ||||
| 
 | ||||
| module Kemal | ||||
| 
 | ||||
|   # The command to run a `Kemal` application. | ||||
|   def self.run | ||||
|     Kemal::CLI.new | ||||
|  | @ -13,6 +12,10 @@ module Kemal | |||
|     config.server = HTTP::Server.new(config.host_binding.not_nil!, config.port, config.handlers) | ||||
|     config.server.not_nil!.ssl = config.ssl | ||||
| 
 | ||||
|     error 404 do |env| | ||||
|       render_404(env) | ||||
|     end | ||||
| 
 | ||||
|     # Test environment doesn't need to have signal trap, built-in images, and logging. | ||||
|     unless config.env == "test" | ||||
|       Signal::INT.trap { | ||||
|  |  | |||
|  | @ -1,18 +1,24 @@ | |||
| class Kemal::CommonExceptionHandler < HTTP::Handler | ||||
|   INSTANCE = new | ||||
| module Kemal | ||||
|   class CommonExceptionHandler < HTTP::Handler | ||||
|     INSTANCE = new | ||||
| 
 | ||||
|   def call(context) | ||||
|     begin | ||||
|       call_next context | ||||
|     rescue ex : Kemal::Exceptions::RouteNotFound | ||||
|       context.response.content_type = "text/html" | ||||
|       Kemal.config.logger.write("Exception: #{ex.inspect_with_backtrace}\n") | ||||
|       return render_404(context) | ||||
|     rescue ex | ||||
|       context.response.content_type = "text/html" | ||||
|       Kemal.config.logger.write("Exception: #{ex.inspect_with_backtrace}\n") | ||||
|       verbosity = Kemal.config.env == "production" ? false : true | ||||
|       return render_500(context, ex.inspect_with_backtrace, verbosity) | ||||
|     def call(context) | ||||
|       begin | ||||
|         call_next(context) | ||||
|       rescue Kemal::Exceptions::RouteNotFound | ||||
|         return Kemal.config.error_handlers[404].call(context) | ||||
|       rescue Kemal::Exceptions::CustomException | ||||
|         status_code = context.response.status_code | ||||
|         if Kemal.config.error_handlers.has_key?(status_code) | ||||
|           context.response.print Kemal.config.error_handlers[status_code].call(context) | ||||
|           return context | ||||
|         end | ||||
|       rescue ex : Exception | ||||
|         context.response.content_type = "text/html" | ||||
|         Kemal.config.logger.write("Exception: #{ex.inspect_with_backtrace}\n") | ||||
|         verbosity = Kemal.config.env == "production" ? false : true | ||||
|         return render_500(context, ex.inspect_with_backtrace, verbosity) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| module Kemal | ||||
|   class Config | ||||
|     INSTANCE = Config.new | ||||
|     HANDLERS = [] of HTTP::Handler | ||||
|     INSTANCE       = Config.new | ||||
|     HANDLERS       = [] of HTTP::Handler | ||||
|     ERROR_HANDLERS = {} of Int32 => HTTP::Server::Context -> String | ||||
|     @ssl : OpenSSL::SSL::Context? | ||||
|     @server : HTTP::Server? | ||||
| 
 | ||||
|  | @ -19,8 +20,6 @@ module Kemal | |||
|       @error_handler = nil | ||||
|       @always_rescue = true | ||||
|       @run = false | ||||
|       @ssl = nil | ||||
|       @server = nil | ||||
|     end | ||||
| 
 | ||||
|     def logger | ||||
|  | @ -47,6 +46,14 @@ module Kemal | |||
|       HANDLERS << handler | ||||
|     end | ||||
| 
 | ||||
|     def error_handlers | ||||
|       ERROR_HANDLERS | ||||
|     end | ||||
| 
 | ||||
|     def add_error_handler(status_code, &handler : HTTP::Server::Context -> _) | ||||
|       ERROR_HANDLERS[status_code] = ->(context : HTTP::Server::Context) { handler.call(context).to_s } | ||||
|     end | ||||
| 
 | ||||
|     def setup | ||||
|       setup_log_handler | ||||
|       setup_error_handler | ||||
|  |  | |||
|  | @ -9,3 +9,7 @@ HTTP_METHODS = %w(get post put patch delete options) | |||
| def ws(path, &block : HTTP::WebSocket, HTTP::Server::Context -> Void) | ||||
|   Kemal::WebSocketHandler.new path, &block | ||||
| end | ||||
| 
 | ||||
| def error(status_code, &block : HTTP::Server::Context -> _) | ||||
|   Kemal.config.add_error_handler status_code, &block | ||||
| end | ||||
|  |  | |||
|  | @ -4,4 +4,11 @@ module Kemal::Exceptions | |||
|       super "Requested path: '#{context.request.override_method as String}:#{context.request.path}' was not found." | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   class CustomException < Exception | ||||
| 
 | ||||
|     def initialize(context) | ||||
|       super "Rendered error with #{context.response.status_code}" | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -33,7 +33,11 @@ class Kemal::RouteHandler < HTTP::Handler | |||
|   def process_request(context) | ||||
|     raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined? | ||||
|     route = context.route_lookup.payload as Route | ||||
|     context.response.print(route.handler.call(context)) | ||||
|     content = route.handler.call(context) | ||||
|     if Kemal.config.error_handlers.has_key?(context.response.status_code) | ||||
|       raise Kemal::Exceptions::CustomException.new(context) | ||||
|     end | ||||
|     context.response.print(content) | ||||
|     context | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,28 +1,3 @@ | |||
| # Template for 403 Forbidden | ||||
| def render_403(context) | ||||
|   template = <<-HTML | ||||
|       <!DOCTYPE html> | ||||
|       <html> | ||||
|       <head> | ||||
|         <style type="text/css"> | ||||
|         body { text-align:center;font-family:helvetica,arial;font-size:22px; | ||||
|           color:#888;margin:20px} | ||||
|         #c {margin:0 auto;width:500px;text-align:left} | ||||
|         </style> | ||||
|       </head> | ||||
|       <body> | ||||
|         <h2>Forbidden</h2> | ||||
|         <h3>Kemal doesn't allow you to see this page.</h3> | ||||
|         <img src="/__kemal__/404.png"> | ||||
|       </body> | ||||
|       </html> | ||||
|   HTML | ||||
|   context.response.content_type = "text/html" | ||||
|   context.response.status_code = 403 | ||||
|   context.response.print template | ||||
|   context | ||||
| end | ||||
| 
 | ||||
| # Template for 404 Not Found | ||||
| def render_404(context) | ||||
|   template = <<-HTML | ||||
|  | @ -79,53 +54,3 @@ def render_500(context, backtrace, verbosity) | |||
|   context.response.print template | ||||
|   context | ||||
| end | ||||
| 
 | ||||
| # Template for 415 Unsupported media type | ||||
| def render_415(context, message) | ||||
|   template = <<-HTML | ||||
|           <!DOCTYPE html> | ||||
|           <html> | ||||
|           <head> | ||||
|             <style type="text/css"> | ||||
|             body { text-align:center;font-family:helvetica,arial;font-size:22px; | ||||
|               color:#888;margin:20px} | ||||
|             #c {margin:0 auto;width:500px;text-align:left} | ||||
|             </style> | ||||
|           </head> | ||||
|           <body> | ||||
|             <h2>Unsupported media type</h2> | ||||
|             <h3>#{message}</h3> | ||||
|             <img src="/__kemal__/404.png"> | ||||
|           </body> | ||||
|           </html> | ||||
|       HTML | ||||
|   context.response.content_type = "text/html" | ||||
|   context.response.status_code = 415 | ||||
|   context.response.print template | ||||
|   context | ||||
| end | ||||
| 
 | ||||
| # Template for 400 Bad request | ||||
| def render_400(context, message) | ||||
|   template = <<-HTML | ||||
|           <!DOCTYPE html> | ||||
|           <html> | ||||
|           <head> | ||||
|             <style type="text/css"> | ||||
|             body { text-align:center;font-family:helvetica,arial;font-size:22px; | ||||
|               color:#888;margin:20px} | ||||
|             #c {margin:0 auto;width:500px;text-align:left} | ||||
|             </style> | ||||
|           </head> | ||||
|           <body> | ||||
|             <h2>Bad request</h2> | ||||
|             <h3>#{message}</h3> | ||||
|             <img src="/__kemal__/404.png"> | ||||
|           </body> | ||||
|           </html> | ||||
|       HTML | ||||
|   context.response.content_type = "text/html" | ||||
|   context.response.status_code = 400 | ||||
|   context.response.print template | ||||
|   context | ||||
| end | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue