diff --git a/lib/travis/api/app/helpers/accept.rb b/lib/travis/api/app/helpers/accept.rb
index ed29d328..b1ffc82b 100644
--- a/lib/travis/api/app/helpers/accept.rb
+++ b/lib/travis/api/app/helpers/accept.rb
@@ -7,6 +7,58 @@ class Travis::Api::App
       DEFAULT_VERSION = 'v1'
       DEFAULT_FORMAT  = 'json'
 
+      class Entry
+        SEPARATORS = Regexp.escape("()<>@,;:\/[]?={}\t ")
+        TOKEN      = /[^#{SEPARATORS}]+/
+        attr_reader :type, :subtype, :quality, :params
+        def initialize(accept_string)
+          @type, @subtype, @quality, @params = parse(accept_string)
+        end
+
+        def <=>(other)
+          [1 - quality, full_type.count('*'), 1 - params.size] <=>
+            [1 - other.quality, other.full_type.count('*'), 1 - other.params.size]
+        end
+
+        def full_type
+          "#{type}/#{subtype}"
+        end
+
+        def mime_type
+          subtype = self.subtype =~ HEADER_FORMAT ? $2 : self.subtype
+          "#{type}/#{subtype}"
+        end
+
+        def version
+          $1 if subtype =~ HEADER_FORMAT
+        end
+
+        def to_s
+          str = "#{full_type}; q=#{quality}"
+          str << "; #{params.map { |k,v| "#{k}=#{v}" }.join('; ')}" if params.length > 0
+          str
+        end
+
+        private
+        def parse(str)
+          # this handles only subset of what Accept header can
+          # contain, only the simplest cases, no quoted strings etc.
+          type, subtype, params = str.scan(%r{(#{TOKEN})/(#{TOKEN})(.*)}).flatten
+          quality = 1
+          if params
+            params = Hash[*params.split(';').map { |p| p.scan /(#{TOKEN})=(#{TOKEN})/ }.flatten]
+            quality = params.delete('q').to_f if params['q']
+          end
+
+          [type, subtype, quality, params]
+        end
+      end
+
+      def accept_entries
+        entries = env['HTTP_ACCEPT'].to_s.delete(' ').to_s.split(',').map { |e| Entry.new(e) }
+        entries.empty? ? [Entry.new('*/*')] : entries.sort
+      end
+
       def accept_version
         @accept_version ||= request.accept.join =~ HEADER_FORMAT && "v#{$1}" || DEFAULT_VERSION
       end
diff --git a/spec/unit/helpers/accept_spec.rb b/spec/unit/helpers/accept_spec.rb
new file mode 100644
index 00000000..11f845ec
--- /dev/null
+++ b/spec/unit/helpers/accept_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+module Travis::Api::App::Helpers
+  describe Accept do
+    class FakeApp < Struct.new(:env)
+      include Accept
+    end
+
+    it 'returns accept entries sorted properly' do
+      accept = "text/html; q=0.2; level=1, application/vnd.travis-ci.2+json, text/*, text/html;level=2; q=0.5"
+      FakeApp.new('HTTP_ACCEPT' => accept).accept_entries.map(&:to_s).should ==
+        ["application/vnd.travis-ci.2+json; q=1", "text/*; q=1", "text/html; q=0.5; level=2", "text/html; q=0.2; level=1"]
+    end
+
+    it 'properly parses params, quality and version' do
+      accept = "application/vnd.travis-ci.2+json; q=0.2; level=1; foo=bar"
+      accept_entry = FakeApp.new('HTTP_ACCEPT' => accept).accept_entries.first
+      accept_entry.quality.should == 0.2
+      accept_entry.params.should == { 'level' => '1', 'foo' => 'bar' }
+      accept_entry.mime_type.should == 'application/json'
+      accept_entry.version.should == '2'
+    end
+
+    it 'returns */* for empty accept header' do
+      accept_entry = FakeApp.new({}).accept_entries.first
+      accept_entry.mime_type.should == '*/*'
+    end
+  end
+end