diff --git a/examples/logging.ru b/examples/logging.ru index d00a9d3..bc0e0dc 100644 --- a/examples/logging.ru +++ b/examples/logging.ru @@ -12,7 +12,7 @@ app = Landline::Server.new do end path "important" do preprocess do |req| - + puts "This is a context for #{request}" if defined? request # Implement logging logic here puts "Client at #{req.headers['remote-addr']} wanted to access something /important!" end diff --git a/examples/session.ru b/examples/session.ru index 08ccb14..00fef29 100644 --- a/examples/session.ru +++ b/examples/session.ru @@ -8,23 +8,21 @@ Landline::Session.hmac_secret = "Your secure signing secret here" app = Landline::Server.new do get "/make_cookie" do session["random_number"] = Random.random_number(100) - text = <<~HTML + <<~HTML
Go check it at this link!
HTML - sleep(20) - text.gsub("#RAND#", request.to_s) end get "/check_cookie" do diff --git a/examples/uploader/lib b/examples/uploader/lib deleted file mode 120000 index 58677dd..0000000 --- a/examples/uploader/lib +++ /dev/null @@ -1 +0,0 @@ -../../lib \ No newline at end of file diff --git a/lib/landline/extensions/session.rb b/lib/landline/extensions/session.rb index 0bb95ee..b991b4d 100644 --- a/lib/landline/extensions/session.rb +++ b/lib/landline/extensions/session.rb @@ -22,6 +22,10 @@ module Landline @hmac_secret ||= ENV.fetch('HMAC_SECRET', SecureRandom.base64(80)) end + # Class for representing session errors + class SessionError < ::StandardError + end + # Class for representing session storage class Session def initialize(cookie, cookies_callback) @@ -40,7 +44,7 @@ module Landline # Retrieve data from session storage # @param key [String, Symbol] serializable key def [](key) - raise StandardError, "session not valid" unless @valid + raise Landline::Session::SessionError, "session not valid" unless @valid unless key.is_a? String or key.is_a? Symbol raise StandardError, "key not serializable" @@ -53,7 +57,7 @@ module Landline # @param key [String, Symbol] serializable key # @param value [Object] serializable data def []=(key, value) - raise StandardError, "session not valid" unless @valid + raise Landline::Session::SessionError, "session not valid" unless @valid unless key.is_a? String or key.is_a? Symbol raise StandardError, "key not serializable" diff --git a/lib/landline/path.rb b/lib/landline/path.rb index faeceac..52db57f 100644 --- a/lib/landline/path.rb +++ b/lib/landline/path.rb @@ -31,8 +31,20 @@ module Landline end end + # Ephemeral proxy class to which callback execution binds + class PathExecutionOrigin + def initialize(request, properties) + @request = request + @properties = Landline::Util::LookupROProxy.new(properties) + end + + attr_accessor :response + attr_reader :request, :properties + end + # Primary building block of request navigation. class Path < Landline::Node + ExecutionOrigin = Landline::PathExecutionOrigin ProcContext = Landline::ProcessorContext Context = Landline::PathContext @@ -50,8 +62,6 @@ module Landline # Contexts setup context = self.class::Context.new(self) context.instance_exec(&setup) - # TODO: This isn't fine - @proccontext = self.class::ProcContext.new(self) end # Method callback on successful request navigation. @@ -96,12 +106,19 @@ module Landline private + # Create an execution context for in-path processing blocks + def get_context(request) + exec_origin = self.class::ExecutionOrigin.new(request, @properties) + self.class::ProcContext.new(exec_origin) + end + # Sequentially run through all filters and drop request if one is false # @param request [Landline::Request] # @return [Boolean] true if request passed all filters def run_filters(request) + proccontext = get_context(request) @filters.each do |filter| - return false unless @proccontext.instance_exec(request, &filter) + return false unless proccontext.instance_exec(request, &filter) end true end @@ -109,8 +126,9 @@ module Landline # Sequentially run all preprocessors on a request # @param request [Landline::Request] def run_preprocessors(request) + proccontext = get_context(request) @preprocessors.each do |preproc| - @proccontext.instance_exec(request, &preproc) + proccontext.instance_exec(request, &preproc) end end @@ -126,7 +144,6 @@ module Landline # @return [Boolean] true if further navigation will be done # @raise [UncaughtThrowError] by default throws :response if no matches found. def process_wrapped(request) - @request = request return false unless run_filters(request) run_preprocessors(request) @@ -149,7 +166,7 @@ module Landline # @param request [Landline::Request] def exit_stack(request, response = nil) request.run_postprocessors(response) - false + response end # Try to perform indexing on the path if possible @@ -174,8 +191,9 @@ module Landline # @param backtrace [Array(String), nil] # @raise [UncaughtThrowError] throws :finish to stop processing def _die(errorcode, backtrace: nil) + proccontext = get_context(request) throw :finish, [errorcode].append( - *@proccontext.instance_exec( + *proccontext.instance_exec( errorcode, backtrace: backtrace, &(@properties["handle.#{errorcode}"] or diff --git a/lib/landline/probe.rb b/lib/landline/probe.rb index d5d5ea0..a5e1db1 100644 --- a/lib/landline/probe.rb +++ b/lib/landline/probe.rb @@ -35,6 +35,17 @@ module Landline end end + # Ephemeral proxy class to which callback execution binds + class ProbeExecutionOrigin + def initialize(request, properties) + @request = request + @properties = Landline::Util::LookupROProxy.new(properties) + end + + attr_accessor :response + attr_reader :request, :properties + end + # Test probe. Also base for all "reactive" nodes. class Probe < Landline::Node # @param path [Object] diff --git a/lib/landline/probe/handler.rb b/lib/landline/probe/handler.rb index a69f05d..f6e1eb6 100644 --- a/lib/landline/probe/handler.rb +++ b/lib/landline/probe/handler.rb @@ -12,8 +12,6 @@ module Landline def initialize(path, **args, &exec) super(path, **args) @callback = exec - @context = Landline::ProbeContext.new(self) - @response = nil end attr_accessor :response @@ -34,20 +32,21 @@ module Landline # @return [Boolean] true if further navigation is possible # @raise [UncaughtThrowError] may raise if die() is called. def process(request) - @response = nil + origin = Landline::ProbeExecutionOrigin.new(request, @properties) + context = Landline::ProbeContext.new(origin) return reject(request) unless request.path.match?(/^\/?$/) - - @request = request + response = catch(:break) do - @context.instance_exec(*request.splat, - **request.param, - &@callback) + context.instance_exec(*request.splat, + **request.param, + &@callback) end return false unless response - - if @response and [String, File, IO].include? response.class - @response.body = response - throw :finish, @response + + oresponse = origin.response + if oresponse and [String, File, IO].include? response.class + oresponse.body = response + throw :finish, oresponse end throw :finish, response end diff --git a/lib/landline/util/lookup.rb b/lib/landline/util/lookup.rb index fb462a2..d92f226 100644 --- a/lib/landline/util/lookup.rb +++ b/lib/landline/util/lookup.rb @@ -33,5 +33,19 @@ module Landline attr_accessor :parent end + + # Read-only lookup proxy + class LookupROProxy + def initialize(lookup) + @lookup = lookup + end + + # Get a value by key + # @param key [#hash] key for value + # @return [Object,nil] + def [](key) + @lookup.[](key) + end + end end end