module Travis::API::V3 class OptIn attr_reader :legacy_stack, :prefix, :router, :accept, :version_header def initialize(legacy_stack, prefix: '/v3', router: Router.new, accept: 'application/vnd.travis-ci.3+', version_header: 'Travis-API-Version') @legacy_stack = legacy_stack @prefix = prefix @router = router @accept = accept @version_header = "HTTP_#{version_header.upcase.gsub(/\W/, '_')}" end def call(env) return redirect(env) if redirect?(env) if matched = matching_env(env) result = @router.call(matched) result, missing = nil, result if cascade?(*result) end result = result || legacy_stack.call(env) pick(result, missing) end def pick(result, missing) return result if missing.nil? return result if result[0] != 404 missing end def redirect?(env) env['PATH_INFO'.freeze] == prefix end def redirect(env) [307, {'Location'.freeze => env['SCRIPT_NAME'.freeze] + prefix + ?/.freeze, 'Conent-Type'.freeze => 'text/plain'.freeze}, []] end def cascade?(status, headers, body) status % 100 == 4 and headers['X-Cascade'.freeze] == 'pass'.freeze end def matching_env(env) for_v3 = from_prefix(env) || from_accept(env) || from_version_header(env) for_v3 == true ? env : for_v3 end def from_prefix(env) return unless prefix and env['PATH_INFO'.freeze].start_with?(prefix + ?/.freeze) env.merge({ 'SCRIPT_NAME'.freeze => env['SCRIPT_NAME'.freeze] + prefix, 'PATH_INFO'.freeze => env['PATH_INFO'.freeze][prefix.size..-1] }) end def from_accept(env) env['HTTP_ACCEPT'.freeze].include?(accept) if accept and env.include?('HTTP_ACCEPT'.freeze) end def from_version_header(env) env[version_header] == '3'.freeze if version_header and env.include?(version_header) end end end