From: Michal Fojtik <[email protected]>

Signed-off-by: Michal fojtik <[email protected]>
---
 server/lib/deltacloud/hardware_profile.rb          |  192 --------------
 .../lib/deltacloud/helpers/application_helper.rb   |  238 -----------------
 server/lib/deltacloud/helpers/assets_helper.rb     |   96 +++++++
 server/lib/deltacloud/helpers/auth_helper.rb       |   73 ++++++
 server/lib/deltacloud/helpers/blob_stream.rb       |  213 ---------------
 server/lib/deltacloud/helpers/conversion_helper.rb |   43 ---
 server/lib/deltacloud/helpers/deltacloud_helper.rb |  273 ++++++++++++++++++++
 server/lib/deltacloud/helpers/driver_helper.rb     |   57 ++++
 .../deltacloud/helpers/hardware_profiles_helper.rb |   50 ----
 server/lib/deltacloud/helpers/json_helper.rb       |   31 ---
 server/lib/deltacloud/helpers/rabbit_helper.rb     |   34 +++
 server/lib/deltacloud/helpers/url_helper.rb        |  112 ++++++++
 12 files changed, 645 insertions(+), 767 deletions(-)
 delete mode 100644 server/lib/deltacloud/hardware_profile.rb
 delete mode 100644 server/lib/deltacloud/helpers/application_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/assets_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/auth_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/blob_stream.rb
 delete mode 100644 server/lib/deltacloud/helpers/conversion_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/deltacloud_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/driver_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/hardware_profiles_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/json_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/rabbit_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/url_helper.rb

diff --git a/server/lib/deltacloud/hardware_profile.rb 
b/server/lib/deltacloud/hardware_profile.rb
deleted file mode 100644
index 162f7af..0000000
--- a/server/lib/deltacloud/hardware_profile.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud
-  class HardwareProfile
-
-    UNITS = {
-      :memory => "MB",
-      :storage => "GB",
-      :architecture => "label",
-      :cpu => "count"
-    }
-
-    def self.unit(name)
-      UNITS[name]
-    end
-
-    class Property
-      attr_reader :name, :kind, :default
-      # kind == :range
-      attr_reader :first, :last
-      # kind == :enum
-      attr_reader :values
-      # kind == :fixed
-      attr_reader :value
-
-      def initialize(name, values, opts = {})
-        @name = name
-        if values.is_a?(Range)
-          @kind = :range
-          @first = values.first
-          @last = values.last
-          @default = values.first
-        elsif values.is_a?(Array)
-          @kind = :enum
-          @values = values
-          @default = values.first
-        else
-          @kind = :fixed
-          @value = values
-          @default = @value
-        end
-        @default = opts[:default] if opts[:default]
-      end
-
-      def unit
-        HardwareProfile.unit(name)
-      end
-
-      def param
-        :"hwp_#{name}"
-      end
-
-      def fixed?
-        kind == :fixed
-      end
-
-      def valid?(v)
-        v = convert_property_value_type(v)
-        case kind
-          # NOTE:
-          # Currently we cannot validate fixed values because of UI
-          # limitation. In UI we have multiple hwp_* properties which overide
-          # each other.
-          # Then provider have one 'static' hardware profile and one
-          # 'customizable' when user select the static one the UI also send
-          # values from the customizable one (which will lead to a validation
-          # error because validation algorith will think that client want to
-          # overide fixed values.
-          #
-          # when :fixed then (v == @default.to_s)
-          when :fixed then true
-          when :range then match_type?(first, v) and (first..last).include?(v)
-          when :enum then match_type?(values.first, v) and values.include?(v)
-          else false
-        end
-      end
-
-      def to_param
-        Validation::Param.new([param, :string, :optional, []])
-      end
-
-      def include?(v)
-        if kind == :fixed
-          return v == value
-        else
-          return values.include?(v)
-        end
-      end
-
-      private
-
-      def match_type?(reference, value)
-        true if reference.class == value.class
-      end
-
-      def convert_property_value_type(v)
-        return v.to_f if v =~ /(\d+)\.(\d+)/
-        return v.to_i if v =~ /(\d+)/
-        v.to_s
-      end
-    end
-
-    class << self
-      def property(prop)
-        define_method(prop) do |*args|
-          values, opts, *ignored = *args
-          instvar = :"@#{prop}"
-          unless values.nil?
-            @properties[prop] = Property.new(prop, values, opts || {})
-          end
-          @properties[prop]
-        end
-      end
-    end
-
-    attr_reader :name
-    property :cpu
-    property :architecture
-    property :memory
-    property :storage
-
-    def initialize(name,&block)
-      @properties   = {}
-      @name         = name
-      instance_eval &block if block_given?
-    end
-
-    def each_property(&block)
-      @properties.each_value { |prop| yield prop }
-    end
-
-    def properties
-      @properties.values
-    end
-
-    def property(name)
-      @properties[name.to_sym]
-    end
-
-    def default?(prop, v)
-      p = @properties[prop.to_sym]
-      p && p.default.to_s == v
-    end
-
-    def to_hash
-      props = []
-      self.each_property do |p|
-        if p.kind.eql? :fixed
-          props << { :kind => p.kind, :value => p.value, :name => p.name, 
:unit => p.unit }
-        else
-          param = { :operation => "create", :method => "post", :name => p.name 
}
-          if p.kind.eql? :range
-            param[:range] = { :first => p.first, :last => p.last }
-          elsif p.kind.eql? :enum
-            param[:enum] = p.values.collect { |v| { :entry => v } }
-          end
-          param
-          props << { :kind => p.kind, :value => p.default, :name => p.name, 
:unit => p.unit, :param => param }
-        end
-      end
-      {
-        :id => self.name,
-        :properties => props
-      }
-    end
-
-    def include?(prop, v)
-      p = @properties[prop]
-      p.nil? || p.include?(v)
-    end
-
-    def params
-      @properties.values.inject([]) { |m, prop|
-        m << prop.to_param
-      }.compact
-    end
-  end
-end
diff --git a/server/lib/deltacloud/helpers/application_helper.rb 
b/server/lib/deltacloud/helpers/application_helper.rb
deleted file mode 100644
index 7a0d58b..0000000
--- a/server/lib/deltacloud/helpers/application_helper.rb
+++ /dev/null
@@ -1,238 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-# Methods added to this helper will be available to all templates in the 
application.
-
-require 'benchmark'
-
-module ApplicationHelper
-
-  include Deltacloud
-
-  def instance_action_method(action)
-    action_method(action, :instances)
-  end
-
-  def action_method(action, collection)
-    collections[collection].operations[action.to_sym].method
-  end
-
-  def driver_has_feature?(feature_name, collection_name = :instances)
-    driver.features(collection_name).any? { |f| f.name == feature_name }
-  end
-
-  def driver_has_auth_features?
-    driver_has_feature?(:authentication_password) || 
driver_has_feature?(:authentication_key)
-  end
-
-  def driver_auth_feature_name
-    'key' if driver_has_feature?(:authentication_key)
-    'password' if driver_has_feature?(:authentication_password)
-  end
-
-  def filter_all(model)
-      filter = {}
-      filter.merge!(:id => params[:id]) if params[:id]
-      filter.merge!(:architecture => params[:architecture]) if 
params[:architecture]
-      filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
-      filter.merge!(:state => params[:state]) if params[:state]
-      filter = {} if filter.keys.size.eql?(0)
-      singular = model.to_s.singularize.to_sym
-      begin
-       @benchmark = Benchmark.measure do
-          @elements = driver.send(model.to_sym, credentials, filter)
-        end
-      rescue
-        @exception = $!
-      end
-      if @elements
-        headers['X-Backend-Runtime'] = @benchmark.real.to_s
-        instance_variable_set(:"@#{model}", @elements)
-        respond_to do |format|
-          format.html { haml :"#{model}/index" }
-          format.xml { haml :"#{model}/index" }
-          format.json { convert_to_json(singular, @elements) }
-        end
-      else
-        report_error(@exception.code)
-      end
-  end
-
-  def show(model)
-    @benchmark = Benchmark.measure do
-      @element = driver.send(model, credentials, { :id => params[:id]} )
-    end
-    headers['X-Backend-Runtime'] = @benchmark.real.to_s
-    instance_variable_set("@#{model}", @element)
-    if @element
-      respond_to do |format|
-        format.html { haml :"#{model.to_s.pluralize}/show" }
-        format.xml { haml :"#{model.to_s.pluralize}/show" }
-        format.json { convert_to_json(model, @element) }
-      end
-    else
-      report_error(404)
-    end
-  end
-
-  def report_error(code=nil)
-    @error, @code = (request.env['sinatra.error'] || @exception), code
-    @code = 500 if not @code and not @error.class.method_defined? :code
-    response.status = @code || @error.code
-    respond_to do |format|
-      format.xml {  haml :"errors/#{@code || @error.code}", :layout => false }
-      format.json { json_return_error(@error) }
-      format.html { haml :"errors/#{@code || @error.code}", :layout => :error }
-    end
-  end
-
-  def instance_action(name)
-    original_instance = driver.instance(credentials, :id => params[:id])
-
-    # If original instance doesn't include called action
-    # return with 405 error (Method is not Allowed)
-    unless 
driver.instance_actions_for(original_instance.state).include?(name.to_sym)
-      return report_error(405)
-    end
-
-    @benchmark = Benchmark.measure do
-      @instance = driver.send(:"#{name}_instance", credentials, params[:id])
-    end
-
-    headers['X-Backend-Runtime'] = @benchmark.real.to_s
-
-    if name == :reboot
-      status 202
-    end
-
-    if name == :destroy
-      respond_to do |format|
-        format.xml { return 204 }
-        format.json { return 204 }
-        format.html { return redirect(instances_url) }
-      end
-    end
-
-    if @instance.class != Instance
-      response['Location'] = instance_url(params[:id])
-      halt
-    end
-
-    respond_to do |format|
-      format.xml { haml :"instances/show" }
-      format.html { haml :"instances/show" }
-      format.json {convert_to_json(:instance, @instance) }
-    end
-  end
-
-  def cdata(text = nil, &block)
-    text ||= capture_haml(&block)
-    "<![CDATA[#{text.strip}]]>"
-  end
-
-  def render_cdata(text)
-    "<![CDATA[#{text.strip}]]>"
-  end
-
-  def link_to_action(action, url, method)
-    capture_haml do
-      haml_tag :form, :method => :post, :action => url, :class => [:link, 
method], :'data-ajax' => 'false' do
-        haml_tag :input, :type => :hidden, :name => '_method', :value => method
-        haml_tag :button, :type => :submit, :'data-ajax' => 'false', 
:'data-inline' => "true" do
-          haml_concat action
-        end
-      end
-    end
-  end
-
-  def link_to_format(format)
-    return unless request.env['REQUEST_URI']
-    uri = request.env['REQUEST_URI']
-    return if uri.include?('format=')
-    uri += uri.include?('?') ? "&format=#{format}" : "?format=#{format}"
-    capture_haml do
-      haml_tag :a, :href => uri, :'data-ajax' => 'false', :'data-icon' => 
'grid' do
-        haml_concat format.to_s.upcase
-      end
-    end
-  end
-
-  def image_for_state(state)
-    state_img = "stopped" if (state!='RUNNING' or state!='PENDING')
-    capture_haml do
-      haml_tag :img, :src => "/images/#{state}" % state.downcase, :title => 
state
-    end
-  end
-
-  # Reverse the entrypoints hash for a driver from drivers.yaml; note that
-  # +d+ is a hash, not an actual driver object
-  def driver_provider(d)
-    result = {}
-    if d[:entrypoints]
-      d[:entrypoints].each do |kind, details|
-        details.each do |prov, url|
-          result[prov] ||= {}
-          result[prov][kind] = url
-        end
-      end
-    end
-    result
-  end
-
-  def header(title, opts={}, &block)
-    opts[:theme] ||= 'b'
-    opts[:back] ||= 'true'
-    capture_haml do
-      haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme], 
:'data-add-back-btn' => opts[:back] do
-        haml_tag :a, :'data-rel' => :back do
-          haml_concat "Back"
-        end if opts[:back] == 'true'
-        haml_tag :h1 do
-          haml_concat title
-        end
-        block.call if block_given?
-      end
-    end
-  end
-
-  def subheader(title, opts={})
-    opts[:theme] ||= 'a'
-    capture_haml do
-      haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme] do
-        haml_tag :p, :class => 'inner-right' do
-          haml_concat title
-        end
-      end
-    end
-  end
-
-  def translate_error_code(code)
-    case code
-      when 400; { :message => "Bad Request" }
-      when 401; { :message => "Unauthorized" }
-      when 403; { :message => "Forbidden" }
-      when 404; { :message => "Not Found" }
-      when 405; { :message => "Method Not Allowed" }
-      when 406; { :message => "Not Acceptable" }
-      when 500; { :message => "Internal Server Error" }
-      when 502; { :message => "Backend Server Error" }
-      when 501; { :message => "Not Supported" }
-    end
-  end
-
-  def new_blob_form_url(bucket)
-    bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
-  end
-end
diff --git a/server/lib/deltacloud/helpers/assets_helper.rb 
b/server/lib/deltacloud/helpers/assets_helper.rb
new file mode 100644
index 0000000..2391da7
--- /dev/null
+++ b/server/lib/deltacloud/helpers/assets_helper.rb
@@ -0,0 +1,96 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Sinatra
+  module StaticAssets
+    module Helpers
+      # In HTML <link> and <img> tags have no end tag.
+      # In XHTML, on the contrary, these tags must be properly closed.
+      #
+      # We can choose the appropriate behaviour with +closed+ option:
+      #
+      #   image_tag "/images/foo.png", :alt => "Foo itself", :closed => true
+      #
+      # The default value of +closed+ option is +false+.
+      #
+      def image_tag(source, options = {})
+        options[:src] = url_for(source)
+        tag("img", options)
+      end
+
+      def stylesheet_link_tag(*sources)
+        list, options = extract_options(sources)
+        list.collect { |source| stylesheet_tag(source, options) }.join("\n")
+      end
+
+      def javascript_script_tag(*sources)
+        list, options = extract_options(sources)
+        list.collect { |source| javascript_tag(source, options) }.join("\n")
+      end
+
+      def link_to(desc, url, options = {})
+        tag("a", options.merge(:href => url_for(url))) do
+          desc
+        end
+      end
+
+      private
+
+      def tag(name, local_options = {})
+        start_tag = "<#{name}#{tag_options(local_options) if local_options}"
+        if block_given?
+          content = yield
+          "#{start_tag}>#{content}</#{name}>"
+        else
+          "#{start_tag}#{"/" if settings.xhtml}>"
+        end
+      end
+
+      def tag_options(options)
+        unless options.empty?
+          attrs = []
+          attrs = options.map { |key, value| 
%(#{key}="#{Rack::Utils.escape_html(value)}") }
+          " #{attrs.sort * ' '}" unless attrs.empty?
+        end
+      end
+
+      def stylesheet_tag(source, options = {})
+        tag("link", { :type => "text/css",
+            :charset => "utf-8", :media => "screen", :rel => "stylesheet",
+            :href => url_for(source) }.merge(options))
+      end
+
+      def javascript_tag(source, options = {})
+        tag("script", { :type => "text/javascript", :charset => "utf-8",
+            :src => url_for(source) }.merge(options)) do
+            end
+      end
+
+      def extract_options(a)
+        opts = a.last.is_a?(::Hash) ? a.pop : {}
+        [a, opts]
+      end
+
+    end
+
+    def self.registered(app)
+      app.helpers StaticAssets::Helpers
+      app.disable :xhtml
+    end
+  end
+
+  register StaticAssets
+end
diff --git a/server/lib/deltacloud/helpers/auth_helper.rb 
b/server/lib/deltacloud/helpers/auth_helper.rb
new file mode 100644
index 0000000..eef2521
--- /dev/null
+++ b/server/lib/deltacloud/helpers/auth_helper.rb
@@ -0,0 +1,73 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# Lazy Basic HTTP authentication. Authentication is only forced when the
+# credentials are actually needed.
+
+module Sinatra
+  module AuthHelper
+    class LazyCredentials
+      def initialize(app)
+        @app = app
+        @provided = false
+      end
+
+      def user
+        credentials!
+        @user
+      end
+
+      def password
+        credentials!
+        @password
+      end
+
+      def provided?
+        @provided
+      end
+
+      private
+      def credentials!
+        if ENV["API_USER"] && ENV["API_PASSWORD"]
+          @user = ENV["API_USER"]
+          @password = ENV["API_PASSWORD"]
+          @provided = true
+        end
+        unless provided?
+          auth = Rack::Auth::Basic::Request.new(@app.request.env)
+          @app.authorize! unless auth.provided? && auth.basic? && 
auth.credentials
+          @user = auth.credentials[0]
+          @password = auth.credentials[1]
+          @provided = true
+        end
+      end
+
+    end
+
+    def authorize!
+      r = "#{Thread.current[:driver]}-deltacloud@#{ENV['HOSTNAME']}"
+      response['WWW-Authenticate'] = %(Basic realm="#{r}")
+      throw(:halt, [401, report_error(401)])
+    end
+
+    # Request the current user's credentials. Actual credentials are only
+    # requested when an attempt is made to get the user name or password
+    def credentials
+      LazyCredentials.new(self)
+    end
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/blob_stream.rb 
b/server/lib/deltacloud/helpers/blob_stream.rb
deleted file mode 100644
index df5cdc6..0000000
--- a/server/lib/deltacloud/helpers/blob_stream.rb
+++ /dev/null
@@ -1,213 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-include Deltacloud
-begin
-  require 'eventmachine'
-  #--
-  # based on the example from
-  #   http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/
-  #--
-  class BlobStream
-    AsyncResponse = [-1, {}, []].freeze
-    def self.call(env, credentials, params)
-      body = DeferrableBody.new
-      #Get the headers out asap. Don't specify a content-type let
-      #the client guess and if they can't they SHOULD default to
-      #'application/octet-stream' anyway as per:
-      #http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
-      EM.next_tick { env['async.callback'].call [200, {
-        'Content-Type' => "#{params['content_type']}",
-        'Content-Disposition' => params["content_disposition"],
-        'Content-Length' => "#{params['content_length']}"}, body]
-      }
-      #call the driver from here. the driver method yields for every chunk
-      #of blob it receives. Then use body.call to write that chunk as received.
-      driver.blob_data(credentials, params[:bucket], params[:blob], params) 
{|chunk| body.call ["#{chunk}"]} #close blob_data block
-      body.succeed
-      AsyncResponse # Tell Thin to not close connection & work other requests
-    end
-  end
-
-  class DeferrableBody
-    include EventMachine::Deferrable
-
-    def call(body)
-      body.each do |chunk|
-        @body_callback.call(chunk)
-      end
-    end
-
-    def each(&blk)
-      @body_callback = blk
-    end
-  end
-rescue LoadError => e
-  # EventMachine isn't available, disable blob streaming
-  class BlobStream
-    def self.call(env, credentials, params)
-      raise NotImplementedError.new("Blob streaming is only supported under 
Thin")
-    end
-  end
-end
-
-module BlobHelper
-
-  def self.extract_blob_metadata_hash(env_hash)
-    meta_array = env_hash.select{|k,v| 
k.match(/^HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i)}
-    metadata = meta_array.inject({}){ |result, array| 
result[array.first.upcase] = array.last; result}
-    metadata
-  end
-
-DELTACLOUD_BLOBMETA_HEADER = /HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i
-
-  #e.g. from HTTP-X-Deltacloud-Blobmeta-FOO:BAR to amz-meta-FOO:BAR
-  def self.rename_metadata_headers(metadata, rename_to)
-    metadata.gsub_keys(DELTACLOUD_BLOBMETA_HEADER, rename_to)
-  end
-
-end
-
-#Monkey patch for streaming blobs:
-# Normally a client will upload a blob to deltacloud and thin will put
-# this into a tempfile. Then deltacloud would stream up to the provider:
-#   i.e.  client =-->>TEMP_FILE-->> deltacloud =-->>STREAM-->> provider
-# Instead we want to recognise that this is a 'PUT blob' operation and
-# start streaming to the provider as the request is received:
-#   i.e.  client =-->>STREAM-->> deltacloud =-->>STREAM-->> provider
-module Thin
-  class Request
-
-    alias_method :move_body_to_tempfile_orig, :move_body_to_tempfile if 
defined?(Thin::Response)
-    private
-      def move_body_to_tempfile
-        if BlobStreamIO::is_put_blob(self)
-          @body = BlobStreamIO.new(self)
-        else
-          move_body_to_tempfile_orig
-        end
-      end
-
-  end
-end
-
-require 'net/http'
-require 'net/https'
-#monkey patch for Net:HTTP
-module Net
-  class HTTP
-
-    alias :request_orig :request
-
-    def request(req, body = nil, blob_stream = nil, &block)
-      unless blob_stream
-        return request_orig(req, body, &block)
-      end
-      @blob_req = req
-      do_start #start the connection
-
-      req.set_body_internal body
-      begin_transport req
-      req.write_header_m @socket,@curr_http_version, edit_path(req.path)
-      @socket
-    end
-
-    class Put < HTTPRequest
-      def write_header_m(sock, ver, path)
-        write_header(sock, ver, path)
-      end
-    end
-
-    def end_request
-      begin
-        res = HTTPResponse.read_new(@socket)
-      end while res.kind_of?(HTTPContinue)
-      res.reading_body(@socket, @blob_req.response_body_permitted?) {
-                                          yield res if block_given? }
-      end_transport @blob_req, res
-      do_finish
-      res
-    end
-  end
-
-end
-
-require 'base64'
-class BlobStreamIO
-
-  attr_accessor :size, :provider, :sock
-
-  def initialize(request)
-    @client_request = request
-    @size = 0
-    bucket, blob = parse_bucket_blob(request.env["PATH_INFO"])
-    user, password = parse_credentials(request.env['HTTP_AUTHORIZATION'])
-    content_type = request.env['CONTENT_TYPE'] || ""
-    #deal with blob_metadata: (X-Deltacloud-Blobmeta-name: value)
-    user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
-    @content_length = request.env['CONTENT_LENGTH']
-    @http, provider_request = driver.blob_stream_connection({:user=>user,
-       :password=>password, :bucket=>bucket, :blob=>blob, :metadata=> 
user_meta,
-       :content_type=>content_type, :content_length=>@content_length })
-    @content_length = @content_length.to_i #for comparison of size in '<< 
(data)'
-    @sock = @http.request(provider_request, nil, true)
-  end
-
-  def << (data)
-    @sock.write(data)
-    @size += data.length
-    if (@size >= @content_length)
-      result = @http.end_request
-      if result.is_a?(Net::HTTPSuccess)
-        @client_request.env["BLOB_SUCCESS"] = "true"
-      else
-        @client_request.env["BLOB_FAIL"] = result.body
-      end
-    end
-  end
-
-  def rewind
-  end
-
-  #use the Request.env hash (populated by the ThinParser) to determine whether
-  #this is a post blob operation. By definition, only get here with a body of
-  # > 112kbytes - thin/lib/thin/request.rb:12 MAX_BODY = 1024 * (80 + 32)
-  def self.is_put_blob(request = nil)
-    path = request.env['PATH_INFO']
-    method = request.env['REQUEST_METHOD']
-    if ( path =~ /^#{Regexp.escape(settings.root_url)}\/buckets/ && method == 
'PUT' )
-      return true
-    else
-      return false
-    end
-  end
-
-  private
-
-  def parse_bucket_blob(request_string)
-    array = request_string.split("/")
-    blob = array.pop
-    bucket = array.pop
-    return bucket, blob
-  end
-
-  def parse_credentials(request_string)
-    decoded = Base64.decode64(request_string.split('Basic ').last)
-    key = decoded.split(':').first
-    pass = decoded.split(':').last
-    return key, pass
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/conversion_helper.rb 
b/server/lib/deltacloud/helpers/conversion_helper.rb
deleted file mode 100644
index 310ba4b..0000000
--- a/server/lib/deltacloud/helpers/conversion_helper.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-require 'deltacloud/base_driver'
-
-module ConversionHelper
-
-  def convert_to_json(type, obj)
-    if ( [ :image, :realm, :instance, :storage_volume, :storage_snapshot, 
:hardware_profile, :key, :bucket, :blob, :firewall, :load_balancer, :address 
].include?( type ) )
-      if Array.eql?(obj.class)
-        data = obj.collect do |o|
-          o.to_hash.merge({ :href => self.send(:"#{type}_url", 
type.eql?(:hardware_profile) ? o.name : o.id ) })
-        end
-        type = type.to_s.pluralize
-      else
-        data = obj.to_hash
-        if type == :blob
-          data.merge!({ :href => self.send(:"bucket_url", 
"#{data[:bucket]}/#{data[:id]}" ) })
-        else
-          data.merge!({ :href => self.send(:"#{type}_url", data[:id]) })
-          if data.has_key?(:hardware_profiles)
-            data[:hardware_profiles] = 
data[:hardware_profiles].inject([]){|res, hwp| res << {hwp.name => {:href => 
self.send(:"hardware_profile_url", hwp.name)}}; res }
-          end
-        end
-      end
-      return { :"#{type}" => data }.to_json
-    end
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb 
b/server/lib/deltacloud/helpers/deltacloud_helper.rb
new file mode 100644
index 0000000..83741f9
--- /dev/null
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -0,0 +1,273 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Helpers
+  module Application
+
+    require 'benchmark'
+
+    def self.included(klass)
+      klass.class_eval do
+        set :root_url, API_ROOT_URL
+        include Sinatra::Rabbit
+        Sinatra::Rabbit.set :root_path, root_url+'/'
+      end
+    end
+
+    def instance_action_method(action)
+      action_method(action, Sinatra::Rabbit::InstancesCollection)
+    end
+
+    def action_method(action, collection)
+      http_method = collection.operation(action).http_method
+      http_method || Sinatra::Rabbit::BaseCollection.http_method_for(action)
+    end
+
+    def filter_all(model)
+      filter = {}
+      filter.merge!(:id => params[:id]) if params[:id]
+      filter.merge!(:architecture => params[:architecture]) if 
params[:architecture]
+      filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
+      filter.merge!(:state => params[:state]) if params[:state]
+      filter = {} if filter.keys.size.eql?(0)
+      singular = model.to_s.singularize.to_sym
+      begin
+        @benchmark = Benchmark.measure do
+          @elements = driver.send(model.to_sym, credentials, filter)
+        end
+      rescue
+        @exception = $!
+      end
+      if @elements
+        headers['X-Backend-Runtime'] = @benchmark.real.to_s
+        instance_variable_set(:"@#{model}", @elements)
+        respond_to do |format|
+          format.html { haml :"#{model}/index" }
+          format.xml { haml :"#{model}/index" }
+          format.json { @media_type=:xml; to_json(haml(:"#{model}/index")) }
+        end
+      else
+        report_error(@exception.respond_to?(:code) ? @exception.code : 500)
+      end
+    end
+
+    def xml_to_json(model)
+      @media_type = :xml
+      to_json(haml(:"#{model}"))
+    end
+
+    def to_json(xml)
+      Crack::XML.parse(xml).to_json
+    end
+
+    def show(model)
+      @benchmark = Benchmark.measure do
+        @element = driver.send(model, credentials, { :id => params[:id]} )
+      end
+      headers['X-Backend-Runtime'] = @benchmark.real.to_s
+      instance_variable_set("@#{model}", @element)
+      if @element
+        respond_to do |format|
+          format.html { haml :"#{model.to_s.pluralize}/show" }
+          format.xml { haml :"#{model.to_s.pluralize}/show" }
+          format.json { @media_type=:xml; 
to_json(haml(:"#{model.to_s.pluralize}/show")) }
+        end
+      else
+        report_error(404)
+      end
+    end
+
+    def report_error(code=nil)
+      @error, @code = (request.env['sinatra.error'] || @exception), code
+      @code = 500 if not @code and not @error.class.method_defined? :code
+      response.status = @code || @error.code
+      respond_to do |format|
+        format.xml {  haml :"errors/#{@code || @error.code}", :layout => false 
}
+        format.html { haml :"errors/#{@code || @error.code}", :layout => 
:error }
+      end
+    end
+
+    def instance_action(name)
+      original_instance = driver.instance(credentials, :id => params[:id])
+
+      # If original instance doesn't include called action
+      # return with 405 error (Method is not Allowed)
+      unless 
driver.instance_actions_for(original_instance.state).include?(name.to_sym)
+        return report_error(405)
+      end
+
+      @benchmark = Benchmark.measure do
+        @instance = driver.send(:"#{name}_instance", credentials, params[:id])
+      end
+
+      headers['X-Backend-Runtime'] = @benchmark.real.to_s
+      status 202
+
+      if name == :destroy
+        respond_to do |format|
+          format.xml { return 204 }
+          format.json { return 204 }
+          format.html { return redirect(instances_url) }
+        end
+      end
+
+      if @instance.class != Instance
+        response['Location'] = instance_url(params[:id])
+        halt
+      end
+
+      respond_to do |format|
+        format.xml { haml :"instances/show" }
+        format.html { haml :"instances/show" }
+        format.json {convert_to_json(:instance, @instance) }
+      end
+    end
+
+    def cdata(text = nil, &block)
+      text ||= capture_haml(&block)
+      "<![CDATA[#{text.strip}]]>"
+    end
+
+    def render_cdata(text)
+      "<![CDATA[#{text.strip}]]>"
+    end
+
+    def link_to_action(action, url, method)
+      capture_haml do
+        haml_tag :form, :method => :post, :action => url, :class => [:link, 
method], :'data-ajax' => 'false' do
+          haml_tag :input, :type => :hidden, :name => '_method', :value => 
method
+          haml_tag :button, :type => :submit, :'data-ajax' => 'false', 
:'data-inline' => "true" do
+            haml_concat action
+          end
+        end
+      end
+    end
+
+    def link_to_format(format)
+      return unless request.env['REQUEST_URI']
+      uri = request.env['REQUEST_URI']
+      return if uri.include?('format=')
+      uri += uri.include?('?') ? "&format=#{format}" : "?format=#{format}"
+      capture_haml do
+        haml_tag :a, :href => uri, :'data-ajax' => 'false', :'data-icon' => 
'grid' do
+          haml_concat format.to_s.upcase
+        end
+      end
+    end
+
+    def image_for_state(state)
+      state_img = "stopped" if (state!='RUNNING' or state!='PENDING')
+      capture_haml do
+        haml_tag :img, :src => "/images/#{state}" % state.downcase, :title => 
state
+      end
+    end
+
+    # Reverse the entrypoints hash for a driver from drivers.yaml; note that
+    # +d+ is a hash, not an actual driver object
+    def driver_provider(d)
+      result = {}
+      if d[:entrypoints]
+        d[:entrypoints].each do |kind, details|
+          details.each do |prov, url|
+            result[prov] ||= {}
+            result[prov][kind] = url
+          end
+        end
+      end
+      result
+    end
+
+    def header(title, opts={}, &block)
+      opts[:theme] ||= 'b'
+      opts[:back] ||= 'true'
+      capture_haml do
+        haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme], 
:'data-add-back-btn' => opts[:back] do
+          haml_tag :a, :'data-rel' => :back do
+            haml_concat "Back"
+          end if opts[:back] == 'true'
+          haml_tag :h1 do
+            haml_concat title
+          end
+          block.call if block_given?
+        end
+      end
+    end
+
+    def subheader(title, opts={})
+      opts[:theme] ||= 'a'
+      capture_haml do
+        haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme] 
do
+          haml_tag :p, :class => 'inner-right' do
+            haml_concat title
+          end
+        end
+      end
+    end
+
+    def translate_error_code(code)
+      case code
+      when 400; { :message => "Bad Request" }
+      when 401; { :message => "Unauthorized" }
+      when 403; { :message => "Forbidden" }
+      when 404; { :message => "Not Found" }
+      when 405; { :message => "Method Not Allowed" }
+      when 406; { :message => "Not Acceptable" }
+      when 500; { :message => "Internal Server Error" }
+      when 502; { :message => "Backend Server Error" }
+      when 501; { :message => "Not Supported" }
+      end
+    end
+
+    def new_blob_form_url(bucket)
+      bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
+    end
+
+    def format_hardware_property(prop)
+      return "&empty;" unless prop
+      u = hardware_property_unit(prop)
+      case prop.kind
+      when :range
+        "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} 
#{u})"
+      when :enum
+        prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: 
#{prop.default} #{u})"
+      else
+        "#{prop.value} #{u}"
+      end
+    end
+
+    def format_instance_profile(ip)
+      o = ip.overrides.collect do |p, v|
+        u = hardware_property_unit(p)
+        "#{p} = #{v} #{u}"
+      end
+      if o.empty?
+        ""
+      else
+        "with #{o.join(", ")}"
+      end
+    end
+
+    private
+    def hardware_property_unit(prop)
+      u = ::Deltacloud::HardwareProfile::unit(prop)
+      u = "" if ["label", "count"].include?(u)
+      u = "vcpus" if prop == :cpu
+      u
+    end
+
+
+
+  end
+end
diff --git a/server/lib/deltacloud/helpers/driver_helper.rb 
b/server/lib/deltacloud/helpers/driver_helper.rb
new file mode 100644
index 0000000..18e0598
--- /dev/null
+++ b/server/lib/deltacloud/helpers/driver_helper.rb
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Helpers
+
+  module Drivers
+
+    def driver_symbol
+      driver_name.to_sym
+    end
+
+    def driver_name
+      Thread.current[:driver] ||= ENV['API_DRIVER']
+    end
+
+    def driver_class_name
+      driver_name.camelize
+    end
+
+    def driver_source_name
+      File.join('..', 'drivers', driver_name, driver_name + '_driver.rb')
+    end
+
+    def driver_class
+      begin
+        m = Deltacloud::Drivers.const_get(driver_class_name)
+        m.const_get(driver_class_name + "Driver").new
+      rescue NameError
+        raise "[ERROR] The driver class name is not defined as 
#{driver_class_name}Driver"
+      end
+    end
+
+    def driver
+      $:.unshift File.join(File.dirname(__FILE__), '..', '..')
+      begin
+        require_relative driver_source_name
+        driver_class
+      rescue LoadError
+        raise "[ERROR] The driver '#{driver_name}' is unknown or not 
installed" unless valid_driver?
+      end
+    end
+
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/hardware_profiles_helper.rb 
b/server/lib/deltacloud/helpers/hardware_profiles_helper.rb
deleted file mode 100644
index 4da9d8c..0000000
--- a/server/lib/deltacloud/helpers/hardware_profiles_helper.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module HardwareProfilesHelper
-
-  def format_hardware_property(prop)
-    return "&empty;" unless prop
-    u = hardware_property_unit(prop)
-    case prop.kind
-      when :range
-      "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} #{u})"
-      when :enum
-      prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: 
#{prop.default} #{u})"
-      else
-      "#{prop.value} #{u}"
-    end
-  end
-
-  def format_instance_profile(ip)
-    o = ip.overrides.collect do |p, v|
-      u = hardware_property_unit(p)
-      "#{p} = #{v} #{u}"
-    end
-    if o.empty?
-      ""
-    else
-      "with #{o.join(", ")}"
-    end
-  end
-
-  private
-  def hardware_property_unit(prop)
-    u = ::Deltacloud::HardwareProfile::unit(prop)
-    u = "" if ["label", "count"].include?(u)
-    u = "vcpus" if prop == :cpu
-    u
-  end
-end
diff --git a/server/lib/deltacloud/helpers/json_helper.rb 
b/server/lib/deltacloud/helpers/json_helper.rb
deleted file mode 100644
index aea16b6..0000000
--- a/server/lib/deltacloud/helpers/json_helper.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module JSONHelper
-
-  def json_features_for_entrypoint(entrypoint)
-    features = driver.features(entrypoint.first).collect { |feature| 
feature.name }
-    features.empty? ? {} : { :features => features }
-  end
-
-  def json_return_error(error)
-    error_output=Hash.new
-    error_output[:url]    =request.env['REQUEST_URI']
-    error_output[:status] =response.status
-    error_output[:message]=error.message if error
-    error_output.to_json
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/rabbit_helper.rb 
b/server/lib/deltacloud/helpers/rabbit_helper.rb
new file mode 100644
index 0000000..252abe2
--- /dev/null
+++ b/server/lib/deltacloud/helpers/rabbit_helper.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+Sinatra::Rabbit::Collection.class_eval do
+
+  def self.standard_index_operation
+    collection_name = @collection_name
+    operation :index, :with_capability => collection_name do
+      control { filter_all collection_name }
+    end
+  end
+
+  def self.standard_show_operation
+    collection_name = @collection_name
+    operation :show, :with_capability => collection_name do
+      control { show collection_name.to_s.singularize.intern }
+    end
+  end
+
+end
+
diff --git a/server/lib/deltacloud/helpers/url_helper.rb 
b/server/lib/deltacloud/helpers/url_helper.rb
new file mode 100644
index 0000000..87bc93e
--- /dev/null
+++ b/server/lib/deltacloud/helpers/url_helper.rb
@@ -0,0 +1,112 @@
+#
+# Based on https://github.com/emk/sinatra-url-for/
+# Commit 1df339284203f8f6ed8d
+#
+# Original license:
+# Copyright (C) 2009 Eric Kidd
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Sinatra
+  module UrlForHelper
+
+    require 'uri'
+
+    def method_missing(name, *args)
+      if name.to_s =~ /^([\w\_]+)_url$/
+        if args.size > 0
+          t = $1
+          if t =~ /^(stop|reboot|destroy|start|attach|detach)_/
+            api_url_for(t.pluralize.split('_').last + '/' + args.first + '/' + 
$1, :full)
+          else
+            api_url_for(t.pluralize, :full) + '/' + "#{args.first}"
+          end
+        else
+          api_url_for($1, :full)
+        end
+      else
+        super
+      end
+    end
+
+    def api_url_for(url_fragment, mode=:path_only)
+      matrix_params = ''
+      if request.params['api']
+        matrix_params += ";provider=%s" % request.params['api']['provider'] if 
request.params['api']['provider']
+        matrix_params += ";driver=%s" % request.params['api']['driver'] if 
request.params['api']['driver']
+      end
+      url_fragment = "/#{url_fragment}" unless url_fragment =~ /^\// # There 
is no need to prefix URI with '/'
+      if mode == :path_only
+        url_for "#{settings.root_url}#{matrix_params}#{url_fragment}", mode
+      else
+        url_for "#{matrix_params}#{url_fragment}", :full
+      end
+    end
+
+    # Construct a link to +url_fragment+, which should be given relative to
+    # the base of this Sinatra app.  The mode should be either
+    # <code>:path_only</code>, which will generate an absolute path within
+    # the current domain (the default), or <code>:full</code>, which will
+    # include the site name and port number.  (The latter is typically
+    # necessary for links in RSS feeds.)  Example usage:
+    #
+    #   url_for "/"            # Returns "/myapp/"
+    #   url_for "/foo"         # Returns "/myapp/foo"
+    #   url_for "/foo", :full  # Returns "http://example.com/myapp/foo";
+    #--
+    # See README.rdoc for a list of some of the people who helped me clean
+    # up earlier versions of this code.
+    def url_for url_fragment, mode=:path_only
+      case mode
+      when :path_only
+        base = request.script_name
+      when :full
+        scheme = request.scheme
+        port = request.port
+        request_host = request.host
+        if request.env['HTTP_X_FORWARDED_FOR']
+          scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || scheme
+          port = request.env['HTTP_X_FORWARDED_PORT']
+          request_host = request.env['HTTP_X_FORWARDED_HOST']
+        end
+        if (port.nil? || port == "" ||
+            (scheme == 'http' && port.to_s == '80') ||
+            (scheme == 'https' && port.to_s == '443'))
+          port = ""
+        else
+          port = ":#{port}"
+        end
+        base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
+      else
+        raise TypeError, "Unknown url_for mode #{mode}"
+      end
+      uri_parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
+      url_escape = uri_parser.escape(url_fragment)
+      # Don't add the base fragment if url_for gets called more than once
+      # per url or the url_fragment passed in is an absolute url
+      if url_escape.match(/^#{base}/) or url_escape.match(/^http/)
+        url_escape
+      else
+        "#{base}#{url_escape}"
+      end
+    end
+  end
+
+end
-- 
1.7.10

Reply via email to