class Ocular::Inputs::HTTP::Input

Constants

DEFAULT_SETTINGS
URI_INSTANCE

Attributes

routes[R]

Public Class Methods

new(settings_factory) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 574
def initialize(settings_factory)
    settings = settings_factory.get(:inputs)[:http]

    @routes = {}
    @settings = DEFAULT_SETTINGS.merge(settings)
    @stopsignal = Queue.new()
    @thread = nil

end

Public Instance Methods

add_delete(script_name, path, options, proxy, &block) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 288
def add_delete(script_name, path, options, proxy, &block)
    name = generate_uri_from_names(script_name, path)
    route('DELETE', name, options, proxy, &block)
end
add_get(script_name, path, options, proxy, &block) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 278
def add_get(script_name, path, options, proxy, &block)
    name = generate_uri_from_names(script_name, path)
    route('GET', name, options, proxy, &block)
end
add_options(script_name, path, options, proxy, &block) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 293
def add_options(script_name, path, options, proxy, &block)
    name = generate_uri_from_names(script_name, path)
    route('OPTIONS', name, options, proxy, &block)
end
add_post(script_name, path, options, proxy, &block) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 283
def add_post(script_name, path, options, proxy, &block)
    name = generate_uri_from_names(script_name, path)
    route('POST', name, options, proxy, &block)
end
body(context, value = nil, &block) click to toggle source

Set or retrieve the response body. When a block is given, evaluation is deferred until the body is read with each.

# File lib/ocular/inputs/http_input.rb, line 423
def body(context, value = nil, &block)
    if block_given?
        def block.each; yield(call) end
        context.response.body = block
    elsif value
        # Rack 2.0 returns a Rack::File::Iterator here instead of
        # Rack::File as it was in the previous API.
        unless context.request.head?
            headers(context).delete 'Content-Length'
        end
        context.response.body = value
    else
        context.response.body
    end
end
build_signature(pattern, keys, &block) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 298
def build_signature(pattern, keys, &block)
    return [pattern, keys, block]
end
call(env) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 417
def call(env)
    dup.call!(env)
end
call!(env) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 439
def call!(env)
    context = WebRunContext.new

    context.request = Request.new(env)
    context.response = Response.new
    context.env = env
    context.params = indifferent_params(context.request.params)

    context.response['Content-Type'] = nil
    invoke(context) do |context|
        dispatch(context)
    end

    unless context.response['Content-Type']
        context.response['Content-Type'] = "text/html"
    end

    context.response.finish
end
call_block(context) { |context| ... } click to toggle source
# File lib/ocular/inputs/http_input.rb, line 505
def call_block(context)
    yield(context)
end
compile(path) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 348
def compile(path)
    if path.respond_to? :to_str
        keys = []

        # Split the path into pieces in between forward slashes.
        # A negative number is given as the second argument of path.split
        # because with this number, the method does not ignore / at the end
        # and appends an empty string at the end of the return value.
        #
        segments = path.split('/', -1).map! do |segment|
            ignore = []

            # Special character handling.
            #
            pattern = segment.to_str.gsub(/[^\?\%\\\/\:\*\w]|:(?!\w)/) do |c|
                ignore << escaped(c).join if c.match(/[\.@]/)
                patt = encoded(c)
                patt.gsub(/%[\da-fA-F]{2}/) do |match|
                    match.split(//).map! { |char| char == char.downcase ? char : "[#{char}#{char.downcase}]" }.join
                end
            end

            ignore = ignore.uniq.join

            # Key handling.
            #
            pattern.gsub(/((:\w+)|\*)/) do |match|
                if match == "*"
                    keys << 'splat'
                    "(.*?)"
                else
                    keys << $2[1..-1]
                ignore_pattern = safe_ignore(ignore)

                ignore_pattern
                end
            end
        end

        # Special case handling.
        #
        if last_segment = segments[-1] and last_segment.match(/\[\^\\\./)
            parts = last_segment.rpartition(/\[\^\\\./)
            parts[1] = '[^'
            segments[-1] = parts.join
        end
        [/\A#{segments.join('/')}\z/, keys]
    elsif path.respond_to?(:keys) && path.respond_to?(:match)
        [path, path.keys]
    elsif path.respond_to?(:names) && path.respond_to?(:match)
        [path, path.names]
    elsif path.respond_to? :match
        [path, []]
    else
        raise TypeError, path
    end
end
define_check_route() click to toggle source
# File lib/ocular/inputs/http_input.rb, line 607
def define_check_route
    pattern, keys = compile("/check")

    (@routes["GET"] ||= []) << build_signature(pattern, keys) do |context|
        [200, "OK\n"]
    end
end
dispatch(context) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 459
def dispatch(context)
    invoke(context) do |context|
        route!(context)
    end

rescue ::Exception => error
    invoke(context) do |context|
        handle_exception!(context, error)
    end
ensure
    
end
encoded(char) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 406
def encoded(char)
    enc = URI_INSTANCE.escape(char)
    enc = "(?:#{escaped(char, enc).join('|')})" if enc == char
    enc = "(?:#{enc}|#{encoded('+')})" if char == " "
    enc
end
escaped(char, enc = URI_INSTANCE.escape(char)) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 413
def escaped(char, enc = URI_INSTANCE.escape(char))
    [Regexp.escape(enc), URI_INSTANCE.escape(char, /./)]
end
generate_uri_from_names(script_name, path) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 264
def generate_uri_from_names(script_name, path)
    if path[0] == "/"
        path = path[1..-1]
    end
    
    if script_name && script_name != ""
        name = script_name + "/" + path
    else
        name = path
    end

    return "/" + name
end
handle_exception!(context, error) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 485
def handle_exception!(context, error)
    context.env['error'] = error

    if error.respond_to? :http_status
        context.response.status = error.http_status

        if error.respond_to? :to_s
            str = error.to_s
            if !str.end_with?("\n")
                str += "\n"
            end
            context.response.body = str
        end
    else
        context.response.status = 500
        puts "Internal Server Error: #{error}"
        puts error.backtrace
    end
end
headers(context, hash = nil) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 569
def headers(context, hash = nil)
    context.response.headers.merge! hash if hash
    context.response.headers
end
indifferent_hash() click to toggle source

Creates a Hash with indifferent access.

# File lib/ocular/inputs/http_input.rb, line 546
def indifferent_hash
    Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
end
indifferent_params(object) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 551
def indifferent_params(object)
    case object
    when Hash
        new_hash = indifferent_hash
        object.each { |key, value| new_hash[key] = indifferent_params(value) }
        new_hash
    when Array
        object.map { |item| indifferent_params(item) }
    else
        object
    end
end
invoke(context) { |context| ... } click to toggle source
# File lib/ocular/inputs/http_input.rb, line 472
def invoke(context)
    res = catch(:halt) { yield(context) }
    if Array === res and Fixnum === res.first
        res = res.dup
        status(context, res.shift)
        body(context, res.pop)
        headers(context, *res)
    elsif res.respond_to? :each
        body(context, res)
    end
    nil # avoid double setting the same response tuple twice
end
process_route(context, pattern, keys, values = []) { |self, values| ... } click to toggle source
# File lib/ocular/inputs/http_input.rb, line 525
def process_route(context, pattern, keys, values = [])
    route = context.request.path_info
    route = '/' if route.empty?
    return unless match = pattern.match(route)
    values += match.captures.map! { |v| URI_INSTANCE.unescape(v) if v }

    if values.any?
        original, @params = context.params, context.params.merge('splat' => [], 'captures' => values)
        keys.zip(values) { |k,v| Array === context.params[k] ? context.params[k] << v : context.params[k] = v if v }
    end

    yield(self, values)

rescue
    context.env['error.params'] = context.params
    raise
ensure
    @params = original if original
end
route(verb, path, options, proxy, &block) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 302
def route(verb, path, options, proxy, &block)
    ::Ocular.logger.debug("Binding #{verb} #{path} to block #{block}")

    eventbase = Ocular::DSL::EventBase.new(proxy, &block)
    (proxy.events[verb] ||= {})[path] = eventbase

    pattern, keys = compile(path)

    (@routes[verb] ||= []) << build_signature(pattern, keys) do |context|
        context.event_signature = [verb, path]
        response = eventbase.exec(context)
        environment = {
            :path => path,
            :options => options,
            :request => context.request,
            :params => context.params,
            :env => context.env,
            :response => response
        }
        context.log_cause("on#{verb}", environment)

        response
    end
end
route!(context) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 509
def route!(context)
    if routes = @routes[context.request.request_method]
        routes.each do |pattern, keys, block|
            process_route(context, pattern, keys) do |*args|
                #env['route'] = block.instance_variable_get(:@route_name)

                #throw :halt, context.exec(&block)
                throw :halt, call_block(context, &block)
            end
        end
    end

    puts "Route missing: #{context.request.request_method} #{context.request.path_info}"
    raise NotFound
end
safe_ignore(ignore) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 327
def safe_ignore(ignore)
    unsafe_ignore = []
    ignore = ignore.gsub(/%[\da-fA-F]{2}/) do |hex|
        unsafe_ignore << hex[1..2]
        ''
    end
    unsafe_patterns = unsafe_ignore.map! do |unsafe|
        chars = unsafe.split(//).map! do |char|
            char == char.downcase ? char : char + char.downcase
        end

        "|(?:%[^#{chars[0]}].|%[#{chars[0]}][^#{chars[1]}])"
    end
    if unsafe_patterns.length > 0
        "((?:[^#{ignore}/?#%]#{unsafe_patterns.join()})+)"
    else
        "([^#{ignore}/?#]+)"
    end
end
start() click to toggle source
# File lib/ocular/inputs/http_input.rb, line 584
def start()
    
    if @settings[:verbose]
      @app = Rack::CommonLogger.new(@app, STDOUT)
    end
    ::Ocular.logger.debug "Puma HTTP server started with settings #{@settings}"

    @thread = Thread.new do
        events_hander = @settings[:silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
        server = ::Puma::Server.new(self, events_hander)

        server.add_tcp_listener @settings[:host], @settings[:port]
        server.min_threads = 0
        server.max_threads = 16

        server.run
        @stopsignal.pop
        server.stop(true)
    end

    define_check_route()
end
status(context, value = nil) click to toggle source
# File lib/ocular/inputs/http_input.rb, line 564
def status(context, value = nil)
    context.response.status = value if value
    context.response.status
end
stop() click to toggle source
# File lib/ocular/inputs/http_input.rb, line 615
def stop()
    @stopsignal << "EXIT"
    @thread.join
end