diff --git a/examples/dirbounce.ru b/examples/dirbounce.ru new file mode 100644 index 0000000..4e99a70 --- /dev/null +++ b/examples/dirbounce.ru @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib") +require 'landline' + +app = Landline::Server.new do + path "/hello" do + bounce + get "/world" do + "Hello world!" + end + end + get "/hello/user" do + "Hello user!" + end +end + +run app diff --git a/examples/errorpages.ru b/examples/errorpages.ru new file mode 100644 index 0000000..06d6fd9 --- /dev/null +++ b/examples/errorpages.ru @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib") +require 'landline' + +app = Landline::Server.new do + get "/hello" do + header "content-type", "text/plain" + "Hello World!" + end + get "/error" do + raise StandardError, "I raised an error! (and that's very sad)" + end + handle do |status, backtrace: nil| + page = ([Landline::Util::HTTP_STATUS[status]] + + (backtrace || [""])).join("\n") + [ + { + "content-length": page.bytesize, + "content-type": "text/plain" + }, + page + ] + end +end + +run app diff --git a/examples/uploader/files/.bash_logout b/examples/uploader/files/.bash_logout new file mode 100644 index 0000000..0e4e4f1 --- /dev/null +++ b/examples/uploader/files/.bash_logout @@ -0,0 +1,3 @@ +# +# ~/.bash_logout +# diff --git a/examples/uploader/files/.bash_profile b/examples/uploader/files/.bash_profile new file mode 100644 index 0000000..5545f00 --- /dev/null +++ b/examples/uploader/files/.bash_profile @@ -0,0 +1,5 @@ +# +# ~/.bash_profile +# + +[[ -f ~/.bashrc ]] && . ~/.bashrc diff --git a/examples/uploader/files/.bashrc b/examples/uploader/files/.bashrc new file mode 100644 index 0000000..dfa913b --- /dev/null +++ b/examples/uploader/files/.bashrc @@ -0,0 +1,10 @@ +# +# ~/.bashrc +# + +# If not running interactively, don't do anything +[[ $- != *i* ]] && return + +# alias ls='ls --color=auto' +# alias grep='grep --color=auto' +# PS1='[\u@\h \W]\$ ' diff --git a/examples/uploader/files/lab5.zip b/examples/uploader/files/lab5.zip new file mode 100644 index 0000000..80a731e Binary files /dev/null and b/examples/uploader/files/lab5.zip differ diff --git a/examples/uploader/form.ru b/examples/uploader/form.ru new file mode 100644 index 0000000..ac494d4 --- /dev/null +++ b/examples/uploader/form.ru @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib") +require 'landline' + +app = Landline::Server.new do + root ENV["PWD"] + index ["index.html"] + post "/" do + formdata = form if form? + files = {} + if formdata + formdata["form_files"].each do |file| + filename = file.filename.split("/").last + `mv #{file.tempfile.path} $PWD/files/#{filename}` + files[file.filename] = "#{filename}" + end + end + erubi(file("index.rhtml"), { formdata: files }).run + end + serve "/files/*" + get "/" do + erubi(file("index.rhtml")).run + end +end + +run app diff --git a/examples/uploader/index.rhtml b/examples/uploader/index.rhtml new file mode 100644 index 0000000..6abb370 --- /dev/null +++ b/examples/uploader/index.rhtml @@ -0,0 +1,31 @@ + + + + Form upload test + + + +

File uploader

+
+

Add files here:

+

+ + + +
+ <% if (defined? formdata) and formdata %> +
+ + <% end %> + + + + diff --git a/examples/uploader/lib b/examples/uploader/lib new file mode 120000 index 0000000..58677dd --- /dev/null +++ b/examples/uploader/lib @@ -0,0 +1 @@ +../../lib \ No newline at end of file diff --git a/examples/uploader/readme.txt b/examples/uploader/readme.txt new file mode 100644 index 0000000..e773bf8 --- /dev/null +++ b/examples/uploader/readme.txt @@ -0,0 +1 @@ +Example of handling forms in Landline diff --git a/lib/landline/dsl/methods_path.rb b/lib/landline/dsl/methods_path.rb index 46ca7d0..04c9449 100644 --- a/lib/landline/dsl/methods_path.rb +++ b/lib/landline/dsl/methods_path.rb @@ -5,6 +5,26 @@ module Landline module DSL # Common path methods module PathMethods + # Bounce request if no handler found instead of issuing 404 + def bounce + @origin.bounce = true + end + + # Create a status code handler on path. + # Recursively applies to all paths unless overridden. + # @param [Integer, nil] Specify a status code to handle + def handle(code = "default", &block) + @origin.properties["handle.#{code}"] = block + end + + # Insert a pass-through pipeline into request processing + # (i.e. for error handling purposes). + # Passed block should yield request (and return yielded data back). + # @param block [#call] block that yields request + def pipeline(&block) + @origin.pipeline = block + end + # Set path index # @param index [Array,String] def index(index) diff --git a/lib/landline/path.rb b/lib/landline/path.rb index 77358bd..bc2a9af 100644 --- a/lib/landline/path.rb +++ b/lib/landline/path.rb @@ -5,12 +5,16 @@ require_relative 'node' require_relative 'dsl/constructors_path' require_relative 'dsl/methods_path' require_relative 'dsl/methods_common' +require_relative 'dsl/methods_probe' +require_relative 'dsl/constructors_probe' require_relative 'util/lookup' module Landline # Execution context for filters and preprocessors. class ProcessorContext include Landline::DSL::CommonMethods + include Landline::DSL::ProbeMethods + include Landline::DSL::ProbeConstructors def initialize(path) @origin = path @@ -54,21 +58,11 @@ module Landline # @return [Boolean] true if further navigation will be done # @raise [UncaughtThrowError] by default throws :response if no matches found. def process(request) - return false unless run_filters(request) - - run_preprocessors(request) - enqueue_postprocessors(request) - @children.each do |x| - if (value = x.go(request)) - return value - end + if @pipeline + @pipeline.call(request) { |inner_req| process_wrapped(inner_req) } + else + process_wrapped(request) end - value = index(request) - return value if value - - _die(404) - rescue StandardError => e - _die(500, backtrace: [e.to_s] + e.backtrace) end # Add a preprocessor to the path. @@ -95,7 +89,9 @@ module Landline @filters.append(block) end - attr_reader :children, :properties + attr_reader :children, :properties, :request + + attr_accessor :bounce, :pipeline private @@ -123,6 +119,31 @@ module Landline request.postprocessors.append(*@postprocessors) end + # Method callback on successful request navigation. + # Finds the next appropriate path to go to. + # (inner pipeline-wrapped handler) + # @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) + enqueue_postprocessors(request) + @children.each do |x| + value = x.go(request) + return value if value + end + value = index(request) + return value if value + + @bounce ? false : _die(404) + rescue StandardError => e + _die(500, backtrace: [e.to_s] + e.backtrace) + ensure + @request = nil + end + # Try to perform indexing on the path if possible # @param request [Landline::Request] # @return [Boolean] true if indexing succeeded @@ -146,11 +167,12 @@ module Landline # @raise [UncaughtThrowError] throws :finish to stop processing def _die(errorcode, backtrace: nil) throw :finish, [errorcode].append( - *(@properties["handle.#{errorcode}"] or - @properties["handle.default"]).call( - errorcode, - backtrace: backtrace - ) + *@proccontext.instance_exec( + errorcode, + backtrace: backtrace, + &(@properties["handle.#{errorcode}"] or + @properties["handle.default"]) + ) ) end end diff --git a/lib/landline/probe/handler.rb b/lib/landline/probe/handler.rb index 660c0cb..b51b945 100644 --- a/lib/landline/probe/handler.rb +++ b/lib/landline/probe/handler.rb @@ -15,10 +15,10 @@ module Landline @context = Landline::ProbeContext.new(self) @response = nil end - + attr_accessor :response attr_reader :request - + # Method callback on successful request navigation. # Runs block supplied with object initialization. # Request's #splat and #param are passed to block. diff --git a/lib/landline/template.rb b/lib/landline/template.rb index 625311c..90a0b2b 100644 --- a/lib/landline/template.rb +++ b/lib/landline/template.rb @@ -88,6 +88,8 @@ module Landline # Import a template from within current template def import(filepath) + filepath = filepath.is_a? File ? filepath : File.open(filepath) + # @sg-ignore newtemp = self.class.new(filepath, {}, parent: @parent) newtemp.binding = @binding newtemp