Today's coderack.org middleware is Rack::ForceDomain. This middleware forces all requests to go to a single domain. This is useful to unite the "www.example.com" and "example.com" domains so they all end up at a single domain.

The Code

require 'rack'

class Rack::ForceDomain
  def initialize(app, domain)
    @app = app
    @domain = domain
  end

  def call(env)
    request = Rack::Request.new(env)
    if @domain and request.host != @domain
      fake_request = Rack::Request.new(env.merge("HTTP_HOST" => @domain))
      Rack::Response.new([], 301, "Location" => fake_request.url).finish
    else
      @app.call(env)
    end
  end
end

Code

Review

When a request's host doesn't match the configured @domain Rack::ForceDomain creates a new Request and Response objects. These two objects are where the good things happen.

fake_request = Rack::Request.new(env.merge("HTTP_HOST" => @domain))

A new Request is created that mimics the current request but with a different HTTP_HOST. This means the scheme (http/https), port, path, and query string are copied over and the host is changed to @domain.

Rack::Response.new([], 301, "Location" => fake_request.url).finish

Then a Response is created as a redirection to the url that's generated from the new Response. #finish is called on the Response to send it back to the client, which causes their browser to redirect.

I'm using some similar code in an application to redirect "example.com" to "www.example.com", but I'm doing it all inside of Rails. If this can be done inside of Rack, I might be able to squeeze out a bit more performance from that case. If it happens enough that is...

Tagged: code-reading rack redirects

My 2 Steps to Becoming A Great Developer has been published in the first issue of Hacker Monthly. I'm impressed by the quality of the printed version, the paper quality is better than most magazines I've read.

Hacker Monthly

Tagged: business writing

Today I'm looking at another rack middleware from coderack.org called Rack::StaticFallback.

This middleware is useful in development if you have users upload files to an application and you don't want to always grab copies of those files when you develop locally. Rack::StaticFallback will rewrite requests to those files and use the actual files from the production server. This is how the request/response looks like for a static file:

  1. Web page renders an image "/uploads/user1.png"
  2. Your local web server tries to load the "/uploads/user1.png" file
  3. Since the file doesn't exist, it sends the request to Rails/Rack
  4. Rack::StaticFallback matches the path and redirects the request to "http://www.productionsite.com/uploads/user1.png"

The Code

coderack.org only listed the gist but I found the full git repository.

module Rack
  # Bounces or redirects requests to missing static files.
  # Partially inspired by [http://menendez.com/blog/using-django-as-pass-through-image-proxy/](http://menendez.com/blog/using-django-as-pass-through-image-proxy/)
  #
  # I.e. could be useful when you want to run the server with production database locally
  # and have user uploaded content fetched transparently from production site.
  #
  # Options:
  #     :mode - [ :off,
  #               :bounce, # returns 404 to any request to static URL,
  #               :fallback ] # any request to static path is redirected to :fallback_static_url
  #     :static_path_regex - Regexp which matches the path to your static files.
  #                          Along the lines of the Capistrano conventions defaults to `%r{/system/(audios|photos|videos)}`
  #     :fallback_static_url - URL of the production site
  #
  # To use with Rails install as a plugin:
  #
  #     script/plugin install git://github.com/dolzenko/rack-static_fallback.git
  #
  # then add the following to your `config/environments/development.rb`
  #
  #     config.middleware.insert_after ::Rack::Lock,
  #                                    ::Rack::StaticFallback, :mode => :fallback,
  #                                                            :static_path_regex => %r{/system/uploads},
  #                                                            :fallback_static_url => "http://myproductionsite.com/"
  #

  class StaticFallback
    def initialize(app, options = {})
      @app = app
      @mode = options[:mode] || :off
      # along the lines of the Capistrano defaults
      @static_path_regex = options[:static_path_regex] || %r{/system/(audios|photos|videos)}
      @fallback_static_url = options[:fallback_static_url] 
    end

    def call(env)
      if env["PATH_INFO"] =~ @static_path_regex
        # If we get here that means that underlying web server wasn't able to serve the static file,
        # i.e. it wasn't found.
        case @mode
          when :off
            # pass the request to next middleware, ultimately Rails
            @app.call(env)

          when :bounce
            # don't pass the request so that it doesn't hit framework, which
            # speeds up things significantly
            not_found

          when :fallback
            if @fallback_static_url
              # redirect request to the production server
              [ 302, { "Location" => ::File.join(@fallback_static_url, env["PATH_INFO"]) }, [] ]
            else
              ActionController::Base.logger.debug "You're using StaticFallback middleware with StaticFallback.mode set to :fallback " <<
                      "however StaticFallback.fallback_static_url has not been set."
              not_found
            end
        end

      else
        @app.call(env)
      end
    end

    def not_found
      [ 404, { "Content-Type" => "text/html", "Content-Length" => "0" }, [] ]
    end
  end
end

Review

Other than the configuration in the initialize method, most of the logic for Rack::StaticFallback is in the #call method which has four different branches (five if you count the web server's case also):

1. Static request with matching file

This is when a static file is requested and the web server is able to send it directly from the filesystem. It isn't shown in the code because it's assumed that the web server would handle this before Rack.

2. Static request with mode off

when :off
  # pass the request to next middleware, ultimately Rails
  @app.call(env)

This happens when a request for a static file comes in and Rack::StaticFallback is configured :off. Since it just passes the request off to the rest of the application, the request will be handled by another middleware and probably trigger Rails' 404 error.

3. Static request with mode bounce

when :bounce
  # don't pass the request so that it doesn't hit framework, which
  # speeds up things significantly
  not_found

This option is interesting. It still serves a 404 error like above, but it doesn't pass the request to the rest of Rack or Rails. This is useful for pages with 100 images and you don't want to wait for Rails spin up and return 404s for each one.

4. Static request with mode fallback

when :bounce
  if @fallback_static_url
    # redirect request to the production server
    [ 302, { "Location" => ::File.join(@fallback_static_url, env["PATH_INFO"]) }, [] ]
  else
    ActionController::Base.logger.debug "You're using StaticFallback middleware with StaticFallback.mode set to :fallback " <<
            "however StaticFallback.fallback_static_url has not been set."
    not_found
  end

Here is where all the interesting code happens. When the @fallback_static_url is configured, it will redirect the request to that url with the file name appended. This will let your production server serve up the request. If the @fallback_static_url isn't configured, then a message is logged and a 404 is returned.

Bug: The logging assumes ActionController is used, which could fail in a non-Rails application like Sinatra.

5. Request that doesn't match the static paths

else
  @app.call(env)
end

The final case happens when the PATH_INFO doesn't match the static paths. This calls the rest of the Rack stack which would end up being sent to Rails to route. This case would be called for every dynamic case.

Tagged: code-reading rack assets

I use the IMAP email integration with Redmine all the time. It's an easy way to send updates to Redmine's issue tracker and I clients love using it. But I always forget what keywords I can use to update the issue. So I'd end up opening the documentation or the code and wasting a bunch of time.

Well, no longer.

Redmine Cheatsheet Screenshot

I've gone through Redmine's code and have created a cheatsheet of how the email integration works, including a list of valid keywords. I've made this available as a free download, feel free to grab a copy and share.

Tagged: redmine products

Today I'm reading the code for Rack::GoogleAnalytics. It's rack middleware I found on coderack.org that will automatically insert the Google Analytics tracking code into every page.

The Code

module Rack #:nodoc:
  class GoogleAnalytics < Struct.new :app, :options

    def call(env)
      status, headers, response = app.call(env)

      if headers["Content-Type"] =~ /text\/html|application\/xhtml\+xml/
        body = ""
        response.each { |part| body << part }
        index = body.rindex("</body>")
        if index
          body.insert(index, tracking_code(options[:web_property_id]))
          headers["Content-Length"] = body.length.to_s
          response = [body]
        end
      end

      [status, headers, response]
    end

    protected

      # Returns JS to be embeded. This takes one argument, a Web Property ID
      # (aka UA number).
      def tracking_code(web_property_id)
        returning_value = <<-EOF
<script type="text/javascript">
if (typeof gaJsHost == 'undefined') {
  var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
  document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
}
</script>
<script type="text/javascript">
try {
var #{options[:prefix]}pageTracker = _gat._getTracker("#{web_property_id}");
EOF
        if options[:multiple_top_level_domains]
          returning_value << <<-EOF          
#{options[:prefix]}pageTracker._setDomainName("none");          
#{options[:prefix]}pageTracker._setAllowLinker(true);          
EOF
        elsif options[:domain_name]
                returning_value << <<-EOF          
      #{options[:prefix]}pageTracker._setDomainName("#{options[:domain_name]}");          
      EOF
        end

        returning_value << <<-EOF
#{options[:prefix]}pageTracker._trackPageview();
} catch(err) {}</script>
EOF
      returning_value
      end
  end
end

Review

Rack::GoogleAnalytics does a few interesting things:

Struct

Instead of using an initialize method like Rack::MemoryBloat did yesterday, it's using a new Struct class.

Generating tracking code

The protected #tracking_code method is responsible for generating the Google Analytics Javascript. There isn't much going on here, just some string substitution and an if statement for the different domain options.

Inserting tracking code

How Rack::GoogleAnalytics inserts the tracking code is interesting. It's running the rest of the application stack and then if the content type is HTML, it adds the tracking code to the string right before the closing body (using String#rindex). This line looks odd to me though:

response.each { |part| body << part }

I think this is collecting all of the response's parts into a single string (body). I'm not sure how Rack works internally, but if it tries to send data to the client in chunks this code might block. At the very least, it will be creating a new string for every response that is the same size as the response body. I wonder if it's possible to just do a string replacement in place.

Tagged: code-reading rack metrics

I've decided to skip over the rest of Facets for now in order to read more application code.

This week I'm going through some coderack.org examples, starting with MemoryBloat. coderack.org is a collection of Rack middlewares, which are little snippets of code that can be added to any Rails or Rack web application.

The Code

module Rack
  class MemoryBloat
    def initialize(app, logger)
      @app = app
      @logger = logger
    end

    def call(env)
      memory_usage_before = memory_usage
      result = @app.call(env)
      memory_usage_after = memory_usage
      @logger.info "MemoryBloat: #{memory_usage_after - memory_usage_before} URL: #{Rack::Request.new(env).url}"
      result
    end

    private
    def memory_usage
      `ps -o rss= -p #{$$}`.to_i
    end
  end
end

Example

Processing WelcomeController#index (for 127.0.0.1 at 2010-06-07 15:13:28) [GET]
Parameters: {"action"=>"index", "controller"=>"welcome"}
Completed in 782ms (View: 722, DB: 5) | 200 OK [http://redmine.acheron/]
MemoryBloat: 4828 URL: http://redmine.acheron/

Notice that this request used 4,828K of memory.

Review

MemoryBloat has a simple implementation but it can be very useful to track down memory usage for specific requests.

#initialize

The initialize method takes the Rack application stack (app) and a logger. When used with Rails, the documentation recommends passing Rails.logger in as the logger.

#call

All rack middlewares run call when the application stack is run. MemoryBloat's call does three things:

  1. It runs the rest of the Rack stack (@app.call(env))
  2. It tracks the memory usage before and after the Rack stack call
  3. It logs the memory usage difference to the @logger

#memory_usage

This method uses ps to find out how much RSS memory the current process is using. It's a crude but effective method, assuming you don't run on Windows.

Tagged: code-reading rack performance

I'm attending OSBridge this week so I'm going to pause the daily code readings. I'll start them back up on Monday the 7th at the latest.

If you're at OSBridge, feel free to find me. I'm using my favorites to plan which sessions I'm thinking of attending.

Tagged: code-reading

This week I'm looking at Facets' Array extensions. Hash, Array, String, and Integer objects are used frequently in Rails so I can take advantage of them faster than more complex classes.

The Code

# File lib/core/facets/array/pad.rb, line 14
  def pad(len, val=nil)
    return dup if self.size >= len.abs
    if len < 0
      Array.new((len+size).abs,val) + self
    else
      self + Array.new(len-size,val)
    end
  end

Example

#!/usr/bin/ruby -wKU
#
# Code Reading #6
require '../base'
require "facets/array/pad"

class Example
  def self.create
    last_ten_transactions = [
                             52.25,
                             100.25,
                             0.45
                            ]
    last_ten_transactions.pad(10, 0)
  end
end

ap Example.create

class ArrayPadTest < Test::Unit::TestCase
  def test_should_pad_the_array_to_10_elements
    result = Example.create
    
    assert_equal 10, result.length
  end

  def test_should_pad_to_the_end_of_the_array
    result = Example.create

    assert_equal [
                  52.25,
                  100.25,
                  0.45,
                  0,
                  0,
                  0,
                  0,
                  0,
                  0,
                  0
                 ], result
  end
end

On github

Review

Array#pad's concept is pretty easy to understand, since padding is used with strings a lot. The implementation is a bit terse so I'll break it up a little bit to help understanding. Array#pad has three different exit conditions:

  1. The array is already bigger than the padding.
  2. #pad is called with a positive padding length.
  3. #pad is called with a negative padding length.

The first exit condition is from the guard clause, return dup if self.size >= len.abs. The reason it's using dup is because Array#pad is returning a new array for all the other conditions. If this case was different, the caller might accidentally use the Array without knowing that's it's the same Array they passed in.

The second exit condition is when #pad is called with a positive padding length. This will create a new array that is prepopulated with val and append it to the calling array, making sure the total length is equal to the len.

The third exit condition is when #pad has a negative padding length. Like before it creates a new array that is prepopulated with val, but this time it prepends the new array onto the calling array.

Prepopulate an Array with values

To prepopulate an array with values, just pass the size and value to Array#new. It can also take a block if you need something more dynamic:

>> Array.new(10, 'ten element array')
[
    [0] "ten element array",
    [1] "ten element array",
    [2] "ten element array",
    [3] "ten element array",
    [4] "ten element array",
    [5] "ten element array",
    [6] "ten element array",
    [7] "ten element array",
    [8] "ten element array",
    [9] "ten element array"
]
>> Array.new(10) { rand(100) }
[
    [0] 93,
    [1] 11,
    [2] 81,
    [3] 84,
    [4] 14,
    [5] 16,
    [6] 6,
    [7] 40,
    [8] 77,
    [9] 88
]
Tagged: code-reading facets array

To finish up this week of code reading, I read through Hash#group_by_value.

The Code

# File lib/core/facets/hash/group_by_value.rb, line 42
  def group_by_value
    res = {}
    each{|k, v| (res[v] ||= []) << k}
    res
  end

Example

#!/usr/bin/ruby -wKU
#
# Code Reading #5
require '../base'
require "facets/hash/group_by_value"

class Example
  def self.create
    # Servers and their OS version string
    {
      :load_balancer => '10.10',
      :web_server_one => '10.10',
      :web_server_two => '10.10',
      :app_server_one => '10.04',
      :app_server_two => '10.04',
      :database_server_one => '9.10',
      :memcached_server_one => 'sid',
      :memcached_server_two => 'sid',
      :background_server => '10.10'
    }
  end
end

ap(Example.create.group_by_value)

class HashGroupByValue < Test::Unit::TestCase
  def test_should_group_servers_by_version
    result = Example.create.group_by_value

    assert result['9.10'].include? :database_server_one

    assert result['10.04'].include? :app_server_one
    assert result['10.04'].include? :app_server_two

    assert result['10.10'].include? :background_server
    assert result['10.10'].include? :load_balancer
    assert result['10.10'].include? :web_server_one
    assert result['10.10'].include? :web_server_two

    assert result['sid'].include? :memcached_server_one
    assert result['sid'].include? :memcached_server_one
  end
  
end

On github

Review

This is another good Hash method that will be useful when working with data. I've used Rails' Hash#group_by a lot but I usually end up with a lot of extra data in the inner elements.

I also like how #group_by_value uses the single statement to initialize the result and add the key to it. (res[v] ||= []) will either:

  • initialize the new key and returns the empty array, or
  • return the existing element (an array)

This lets << k append onto the array directly. Compare that one line to the alternative and it's easy to see how elegant the initializer can be.

res[v] ||= []
res[v] << k
Tagged: code-reading facets hash

Rails uses Hashes a lot for passing options to methods. I typically use Hash#merge to add any default options to them but I've always hated the syntax and frequently got it backwards.

options = {:value => 'default', :size => 30}.merge(options)

Facets has a Hash#reverse_merge that gets the order right. And the implementation is so simple, I'm kicking myself for not using it sooner.

The Code

# File lib/core/facets/hash/merge.rb, line 15
  def reverse_merge(other)
    other.merge(self)
  end

Example

#!/usr/bin/ruby -wKU
#
# Code Reading #4
require '../base'
require "facets/hash/merge"

class Example
  def self.create
    {
      :users => [:edavis],
      :servers => [:app1, :app2, :app3]
    }
  end
end

ap(Example.create.reverse_merge({
                                  :shell => '/bin/bash',
                                  :users => [:rails]
                                }))

class HashReverseMerge < Test::Unit::TestCase
  def test_should_combine_hashes
    @example = Example.create.reverse_merge({:shell => '/bin/bash'})
    
    assert_equal '/bin/bash', @example[:shell]
    assert_equal [:edavis], @example[:users]
  end

  def test_should_let_the_caller_win
    @example = Example.create.reverse_merge({
                                              :shell => '/bin/bash',
                                              :users => [:rails]
                                            })
    
    assert_equal '/bin/bash', @example[:shell]
    assert_equal [:edavis], @example[:users]
  end
end

On github

Review

Now I can rewrite the default options like:

options = options.reverse_merge({:value => 'default', :size => 30})

(There are also bang versions, #merge! and #reverse_merge!)

Tagged: code-reading facets hash