benchmark

The built-in profiler, and even ruby-prof, add a lot of overhead to the interpreter. This reduces their usefulness. If I don’t know why my program is slow, I use ruby-prof. However…

benchmark, i choose you!

Sometimes I already know the source of the problem, and just need to see if my changes are making a difference or not. So I added a little guy to my .irbrc file:

def benchmark
  cur = Time.now
  result = yield
  print "#{cur = Time.now - cur} seconds"
  puts " (#{(cur / $last_benchmark * 100).to_i - 100}% change)" rescue puts ""
  $last_benchmark = cur
  result
end

Now I can benchmark {} any block and get the wall clock running time, as well as the percent change (+ or -) from the last run. As they say on the street: schwing!

cgi.rb vulnerability hotfix

I’ve constructed a hotfix for the cgi.rb vulnerability of yesterday.

what’s fixed?

Fixes an exploitable bug in CGI multipart parsing which affects Ruby <= 1.8.5 when multipart boundary attribute contains a non-halting regular expression string. The boundary searcher in the CGI module does not properly escape the user-supplied parameter and will execute arbitrary regular expressions. The fix adds escaping for the user data.

See the included test to see how the vulnerability works.

This is fix is cumulative with previous CGI multipart vulnerability fixes; see version 1.0.0 of the gem by Zed Shaw.

scope

  • Affected: standalone CGI, Mongrel, WEBrick
  • Unaffected: FastCGI
  • Unknown: mod_ruby

resources

Official vulnerability announcement, my original post, and this post.

license

Licensed under the same license as Ruby itself. Software contains the work of others.

rails affected by new cgi.rb vulnerability

Another denial-of-service vulnerability has been discovered in cgi.rb’s multipart mime parsing. You can read Zed’s message about it here. The diff is here.

update

I have an exploit, and will disclose it tomorrow. Basically, the multipart boundary attribute is inserted directly into the regular expression that parses the message contents. This means you can use a regular expression sequence that will cause an infinite loop, via a POST request.

Regular expressions in practice do not always halt, because of look-behinds and other features like that.

scope of the problem

As far as I can tell, this does not affect mongrel itself unless you specifically use cgi.rb’s multipart mime parsing in your mongrel handler. Camping does not use cgi.rb at all.

Rails, however, uses it. Rails on mongrel can be bogged down by a series of malicious requests, and Rails on webrick can be completely halted by a single one. Tests suggest that fastcgi is not affected.

You can read more about the multipart boundary parameter in RFC 2388.

polymorphs 19

Third time’s the charm. Thanks to Xardion and Agile’s efforts, more bugs were discovered in double polymorphism. But new tests that failed now work, so I think it is safe to say that the feature is complete.

api change

There is a tiny API change if you use the :rename_individual_collections option. For example:

class Dog < ActiveRecord::Base
  has_many_polymorphs :bones,
      :from => [:real, :rawhide, :rubber],
      :rename_individual_collections => true
end 

The parents (dogs) can now be accessed from the children (bones) via .dogs_of_bones. This is to avoid a conflict with .bones_dogs, which is the default name for the join records themselves.

new debugging facility

If you glance at the beginning of the lib/has_many_polymorphs.rb source, you will see instructions for making the plugin generate real Ruby code explaining all of the ActiveRecord relationships set up. This is for debugging purposes.

You can’t use the code directly because it doesn’t include any of the special methods defined here and there. But it’s great for understanding what has_many_polymorphs is doing to your model relationships.

Or, you can use it just to see what a ridiculous number of associations have to get set up to make everything work. The test fixtures generate 68 ActiveRecord associations (as well as 16 plugin associations).

has_many_polymorphs bugfix release

Get version 18 from the usual place.

update

Now also fixed a bug where doubly polymorphic parents weren’t being strict about which children they returned (thanks to Xardion and Agile for the discovery).

what’s changed

  • now supports legacy primary key names (thanks Paul Wright)
  • fixes a bug related to instantiating attributes of namespaced models
  • fixes a bug that prevented doubly-polymorphic children from accessing their parents sometimes
  • fixes a very obscure bug when running on sqlite3 (specifically, this)

Now it has no more bugs. You may uncross your fingers. Thanks goes to Hildolfur for putting the plugin through the wringer and revealing the last three problems.

inline rescue vs. respond_to? cage fight

Which is faster? Inline rescue, or classic branching based on the respond_to? method? Let’s face them off.

ding

Download this, then run like so:

$ ruby test_rescue.rb success respond_to
0.947819 seconds
$ ruby test_rescue.rb success rescue
0.575646 seconds
$ ruby test_rescue.rb failure respond_to
0.789487 seconds
$ ruby test_rescue.rb failure rescue
16.1751 seconds

This suggests that a clean rescue path is about twice as fast as a successful respond_to? condition. But a raised rescue is 20 times slower than a failed respond_to?.

a champion! sort of

Excusing my slipshod math and neglect of all other relevant factors, this means that in time-critical code paths we should use respond_to? unless the path is predicted to fail less than 2.5% of the time. So it depends.

easily stop double posts

You have a comment form. Someone clicks twice. Oh noes! Double post!

think first

What’s the real problem with double posting? It’s not that the user clicked “submit” several times. The problem is that we have a duplicate record in our database. So instead of fixing this at the view level, we can solve it at the model level in a one-line validation:

class Comment < ActiveRecord::Base
  belongs_to :post
  validates_uniqueness_of :body, :scope => [:post_id, :name]
end

scope

The above validation acts exactly like a multicolumn database constraint. The order of the fields doesn’t matter, because what gets checked is the uniqueness of the combination of fields (:body, :post_id, and :name). So if someone wants to comment “cool!” on every post, they can do it, but they can’t comment “cool!” twice on the same post.

Scoping is all the rage right now. But uniqueness scoping is not really related.

show me show me

This solution is implemented here, on Snax. Also, we rolled it into Chow not too long ago. I work on Chow these days. It’s sweet.

directed double-polymorphic associations

In a frenzy of Bluetooth-enabled coding from the local diner, I have implemented double polymorphic associations in the has_many_polymorphs plugin. This lets you create a multi-class directed graph in ActiveRecord with great ease.

show, don’t tell

For example, say we wanted to model glue. We want to be able to glue PopsicleSticks and Leaves to themselves, but also to Paper. We will make a join model called Adhesion for this:

example
class Adhesion < ActiveRecord::Base
  belongs_to :glue_receiver, :polymorphic => true
  belongs_to :glue_applier, :polymorphic => true

  acts_as_double_polymorphic_join :glue_receivers =>
        [:popsicle_sticks, :leaves, :papers],
                                  :glue_appliers =>
        [:popsicle_sticks, :leaves]
end

This means that a PopsicleStick will have a glue_receivers polymorphic collection that can accept anything in the :glue_receivers list, above. A Paper, though, will not have a .glue_receivers method. It will have a .glue_appliers method, but it is not itself a :glue_applier. This is tricky. Just remember that the lists in the acts_as call are the types of children for that relationship, not the types of parents.

Also, using the individual typed collections (e.g. PopsicleStick#leaves) will always get you the children that belong to the record, instead of the parents that own the record. In this case it will fetch the Leaves from a PopsicleStick object’s .glue_receivers.

warning! class-reloading laser in use!

The API is a little different because there is no parent class that can act as a controller. Things are instead centralized in the join model.

This means that you have to reference the join class (either with load(), by evaluating its bare class name, or another way) before the associations will be injected into the “real” classes. Rails’ selective reloading in the development environment can lead to trouble—a modified class will get reloaded and forget its relationship to the join. Keep this in mind.

crazy clown collections

Combining this with the other plugin features leads to controlled chaos. Self-referential directed double-polymorphic namespaced STI associations are (at least according to my tests) fully supported.

Please try it out and let me know if you have trouble. I really appreciate the filing of bugs.

namespaced model support in has_many_polymorphs

Release 16 of the has_many_polymorphs plugin is out. It adds support for namespaced models (by special request), and fixes a Postgres bug.

example
class Scents::Bacon < ActiveRecord::Base
  has_many_polymorphs :sniffers,
                      :from => [:dogs, :"forest_animals/hedgehogs"],
                      :through => "actions/sniffings"
                      # (join model is Actions::Sniffing)
end

Please let me know if you have any problems. I am a great expert on namespaced models in Rails now. It’s not always pretty. However, it’s not as bad as they say.

mongrel denial of service vulnerability

There is a denial of service vulnerability for Ruby applications that either use cgi.rb, or run on Mongrel or Litespeed. This means that Rails is affected. The fix is described below.

problem

Zed Shaw makes a full report here, explaining that:

…there has been an exploitable bug in the Ruby CGI library named cgi.rb, which allows anyone on the internet to send a single HTTP request to any Ruby program (not just Mongrel) using cgi.rb multipart parsing with a malformed MIME body that causes the Ruby process to go into a 99% CPU infinite loop, killing it.

fix

The quickest fix is to update your mongrel version. You have to use --source, though, because 0.3.14 isn’t in the main repository yet:

sudo gem install mongrel --source=http://mongrel.rubyforge.org/releases

Be warned. This gem breaks relative paths in X-Sendfile headers with Apache 2.2 (and possibly others). Use File.expand_path() to convert to absolute before you set the header.

more information

See the mailing list message for alternative fixes if you don’t use mongrel or if upgrading the mongrel gem is not an option for you.

Thanks to cdcarter for the tip.