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 %>
+
+
+ <% formdata.each do |key, part| %>
+ - <%= key %>: <%= part %>
+ <% end %>
+
+ <% 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