diff --git a/sinatra-contrib/lib/sinatra/link_header.rb b/sinatra-contrib/lib/sinatra/link_header.rb
new file mode 100644
index 00000000..c7fc1903
--- /dev/null
+++ b/sinatra-contrib/lib/sinatra/link_header.rb
@@ -0,0 +1,84 @@
+require 'sinatra/base'
+
+module Sinatra
+ ##
+ # Helper methods for generating Link HTTP headers and HTML tags.
+ module LinkHeader
+ ##
+ # Set Link HTTP header and returns HTML tags for telling the browser to
+ # prefetch given resources (only supported by Opera and Firefox at the
+ # moment).
+ def prefetch(*urls)
+ link(:prefetch, *urls)
+ end
+
+ ##
+ # Sets Link HTTP header and returns HTML tags for using stylesheets.
+ def stylesheet(*urls)
+ urls << {} unless urls.last.respond_to? :to_hash
+ urls.last[:type] ||= mime_type(:css)
+ link(:stylesheet, *urls)
+ end
+
+ ##
+ # Sets Link HTTP header and returns corresponding HTML tags.
+ #
+ # Example:
+ #
+ # # Sets header:
+ # # Link: ; rel="next"
+ # # Returns String:
+ # # ''
+ # link '/foo', :rel => :next
+ #
+ # # Multiple URLs
+ # link :stylesheet, '/a.css', '/b.css'
+ def link(*urls)
+ opts = urls.last.respond_to?(:to_hash) ? urls.pop : {}
+ opts[:rel] = urls.shift unless urls.first.respond_to? :to_str
+ options = opts.map { |k, v| " #{k}=#{v.to_s.inspect}" }
+ html_pattern = ""
+ http_pattern = ["<%s>", *options].join ";"
+ link = (response["Link"] ||= "")
+
+ urls.map do |url|
+ link << "\n" unless link.empty?
+ link << (http_pattern % url)
+ html_pattern % url
+ end.join "\n"
+ end
+
+ ##
+ # Takes the current value of th Link header(s) and generates HTML tags
+ # from it.
+ #
+ # Example:
+ #
+ # get '/' do
+ # # You can of course use fancy helpers like #link, #stylesheet
+ # # or #prefetch
+ # response["Link"] = '; rel="next"'
+ # haml :some_page
+ # end
+ #
+ # __END__
+ #
+ # @@ layout
+ # %head= link_headers
+ # %body= yield
+ def link_headers
+ yield if block_given?
+ return "" unless response.include? "Link"
+ response["Link"].lines.map do |line|
+ url, *opts = line.split(';').map(&:strip)
+ ""
+ end.join "\n"
+ end
+
+ def self.registered(base)
+ puts "WARNING: #{self} is a helpers module, not an extension."
+ end
+ end
+
+ helpers LinkHeader
+end
diff --git a/sinatra-contrib/spec/link_header_spec.rb b/sinatra-contrib/spec/link_header_spec.rb
new file mode 100644
index 00000000..cf8d30b0
--- /dev/null
+++ b/sinatra-contrib/spec/link_header_spec.rb
@@ -0,0 +1,100 @@
+require 'backports'
+require_relative 'spec_helper'
+
+describe Sinatra::LinkHeader do
+ before do
+ mock_app do
+ helpers Sinatra::LinkHeader
+ before('/') { link 'something', :rel => 'from-filter', :foo => :bar }
+
+ get '/' do
+ link :something, 'booyah'
+ end
+
+ get '/style' do
+ stylesheet '/style.css'
+ end
+
+ get '/prefetch' do
+ prefetch '/foo'
+ end
+
+ get '/link_headers' do
+ response['Link'] = " ;bar=\"baz\""
+ stylesheet '/style.css'
+ prefetch '/foo'
+ link_headers
+ end
+ end
+ end
+
+ describe :link do
+ it "sets link headers" do
+ get '/'
+ headers['Link'].lines.should include('; rel="something"')
+ end
+
+ it "returns link html tags" do
+ get '/'
+ body.should == ''
+ end
+
+ it "takes an options hash" do
+ get '/'
+ elements = ["", "foo=\"bar\"", "rel=\"from-filter\""]
+ headers['Link'].lines.first.strip.split('; ').sort.should == elements
+ end
+ end
+
+ describe :stylesheet do
+ it 'sets link headers' do
+ get '/style'
+ headers['Link'].should match(%r{^;})
+ end
+
+ it 'sets type to text/css' do
+ get '/style'
+ headers['Link'].should include('type="text/css"')
+ end
+
+ it 'sets rel to stylesheet' do
+ get '/style'
+ headers['Link'].should include('rel="stylesheet"')
+ end
+
+ it 'returns html tag' do
+ get '/style'
+ body.should match(%r{^;})
+ end
+
+ it 'sets rel to prefetch' do
+ get '/prefetch'
+ headers['Link'].should include('rel="prefetch"')
+ end
+
+ it 'returns html tag' do
+ get '/prefetch'
+ body.should == ''
+ end
+ end
+
+ describe :link_headers do
+ it 'generates html for all link headers' do
+ get '/link_headers'
+ body.should include('')
+ body.should include('')
+ end
+ end
+end