travis-api/lib/travis/api/app/middleware/user_agent_tracker.rb
2014-10-28 11:10:25 +01:00

86 lines
2.9 KiB
Ruby

require 'travis/api/app'
require 'useragent'
class Travis::Api::App
class Middleware
class UserAgentTracker < Middleware
WEB_BROWSERS = [
"Internet Explorer",
"Webkit", "Chrome", "Safari", "Android",
"Firefox", "Camino", "Iceweasel", "Seamonkey", "Android",
"Opera", "Mozilla"
]
before(agent: /^$/) do
::Metriks.meter("api.user_agent.missing").mark
halt(400, "error" => "missing User-Agent header") if Travis::Features.feature_active?(:require_user_agent)
end
before(agent: /^.+$/) do
agent = UserAgent.parse(request.user_agent)
case agent.browser
when *WEB_BROWSERS then mark_browser
when "curl", "Wget" then mark(:console, agent.browser)
when "travis-api-wrapper" then mark(:script, :node_js, agent.browser)
when "TravisPy" then mark(:script, :python, agent.browser)
when "Ruby", "PHP", "Perl", "Python" then mark(:script, agent.browser, :vanilla)
when "Faraday" then mark(:script, :ruby, :vanilla)
when "Travis" then mark_travis(agent)
else mark_unknown
end
end
def mark_browser
# allows a JavaScript Client to set X-User-Agent, for instance to "travis-web" in travis-web
x_agent = UserAgent.parse(env['HTTP_X_USER_AGENT'] || 'unknown').browser
mark(:browser, x_agent)
end
def mark_travis(agent)
os, *rest = agent.application.comment
ruby, rubygems, command = "unknown", "unknown", nil
rest.each do |comment|
case comment
when /^Ruby (\d\.\d.\d)/ then ruby = $1
when /^RubyGems (.+)$/ then rubygems = $1
when /^command (.+)$/ then command = $1
end
end
# "Ubuntu 12.04 like Linux" => "linux.ubuntu.12.04"
if os =~ /^(.+) (\S+) like (\S+)$/
os = "#{$3}.#{$1}.#{$2[/\d+\.\d+/]}"
end
if command
mark(:cli, version: agent.version, ruby: ruby, rubygems: rubygems, command: command, os: os)
else
# only track ruby version and library version for non-cli usage
mark(:script, :ruby, :travis, version: agent.version, ruby: ruby)
end
end
def mark_unknown
logger.warn "[user-agent-tracker] Unknown User-Agent: %p" % request.user_agent
mark(:unknown)
end
def track_key(string)
string.to_s.downcase.gsub(/[^a-z0-9\-\.]+/, '_')
end
def mark(*keys)
key = "api.user_agent"
keys.each do |subkey|
if subkey.is_a? Hash
subkey.each_pair { |k, v| ::Metriks.meter("#{key}.#{track_key(k)}.#{track_key(v)}").mark }
else
::Metriks.meter(key << "." << track_key(subkey)).mark
end
end
end
end
end
end