on 404 redirect for /owner/name paths on v1

This commit is contained in:
Sven Fuchs 2012-10-09 23:16:27 +02:00
parent a7d72beefc
commit f8bd49e88b
6 changed files with 177 additions and 116 deletions

View File

@ -16,84 +16,93 @@ require 'newrelic_rpm'
# run Travis::Api::App.new
#
# Requires TLS in production.
class Travis::Api::App
autoload :AccessToken, 'travis/api/app/access_token'
autoload :Base, 'travis/api/app/base'
autoload :Endpoint, 'travis/api/app/endpoint'
autoload :Extensions, 'travis/api/app/extensions'
autoload :Helpers, 'travis/api/app/helpers'
autoload :Middleware, 'travis/api/app/middleware'
autoload :Responders, 'travis/api/app/responders'
module Travis::Api
ACCEPT_VERSION = /vnd\.travis-ci\.(\d+)\+/
DEFAULT_VERSION = 'v2'
Rack.autoload :SSL, 'rack/ssl'
# Used to track if setup already ran.
def self.setup?
@setup ||= false
def version(string)
string =~ ACCEPT_VERSION && "v#{$1}" || DEFAULT_VERSION
end
# Loads all endpoints and middleware and hooks them up properly.
# Calls #setup on any middleware and endpoint.
#
# This method is not threadsafe, but called when loading
# the environment, so no biggy.
def self.setup(options = {})
setup! unless setup?
Endpoint.set(options)
end
class App
autoload :AccessToken, 'travis/api/app/access_token'
autoload :Base, 'travis/api/app/base'
autoload :Endpoint, 'travis/api/app/endpoint'
autoload :Extensions, 'travis/api/app/extensions'
autoload :Helpers, 'travis/api/app/helpers'
autoload :Middleware, 'travis/api/app/middleware'
autoload :Responders, 'travis/api/app/responders'
def self.new(options = {})
setup(options) if options
super()
end
Rack.autoload :SSL, 'rack/ssl'
attr_accessor :app
# Used to track if setup already ran.
def self.setup?
@setup ||= false
end
def initialize
@app = Rack::Builder.app do
use Hubble::Rescuer, env: Travis.env, codename: ENV['CODENAME'] if Endpoint.production? && ENV['HUBBLE_ENDPOINT']
use Rack::Protection::PathTraversal
use Rack::SSL if Endpoint.production?
use Rack::Deflater
use Rack::PostBodyContentTypeParser
use Rack::JSONP
use ActiveRecord::ConnectionAdapters::ConnectionManagement
# Loads all endpoints and middleware and hooks them up properly.
# Calls #setup on any middleware and endpoint.
#
# This method is not threadsafe, but called when loading
# the environment, so no biggy.
def self.setup(options = {})
setup! unless setup?
Endpoint.set(options)
end
use Rack::Config do |env|
env['travis.global_prefix'] = env['SCRIPT_NAME']
def self.new(options = {})
setup(options) if options
super()
end
attr_accessor :app
def initialize
@app = Rack::Builder.app do
use Hubble::Rescuer, env: Travis.env, codename: ENV['CODENAME'] if Endpoint.production? && ENV['HUBBLE_ENDPOINT']
use Rack::Protection::PathTraversal
use Rack::SSL if Endpoint.production?
use Rack::Deflater
use Rack::PostBodyContentTypeParser
use Rack::JSONP
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use Rack::Config do |env|
env['travis.global_prefix'] = env['SCRIPT_NAME']
end
Middleware.subclasses.each { |m| use(m) }
Endpoint.subclasses.each { |e| map(e.prefix) { run(e.new) } }
end
end
# Rack protocol
def call(env)
app.call(env)
end
private
def self.setup!
setup_travis
load_endpoints
setup_endpoints
@setup = true
end
Middleware.subclasses.each { |m| use(m) }
Endpoint.subclasses.each { |e| map(e.prefix) { run(e.new) } }
end
def self.setup_travis
Travis::Amqp.config = Travis.config.amqp
Travis::Database.connect
Travis.services = Travis::Services
end
def self.load_endpoints
Backports.require_relative_dir 'app/middleware'
Backports.require_relative_dir 'app/endpoint'
end
def self.setup_endpoints
Base.subclasses.each(&:setup)
end
end
# Rack protocol
def call(env)
app.call(env)
end
private
def self.setup!
setup_travis
load_endpoints
setup_endpoints
@setup = true
end
def self.setup_travis
Travis::Amqp.config = Travis.config.amqp
Travis::Database.connect
Travis.services = Travis::Services
end
def self.load_endpoints
Backports.require_relative_dir 'app/middleware'
Backports.require_relative_dir 'app/endpoint'
end
def self.setup_endpoints
Base.subclasses.each(&:setup)
end
end

View File

@ -0,0 +1,30 @@
require 'travis/api/app'
class Travis::Api::App
class Middleware
class Rewrite < Middleware
V1_REPO_URL = %r(^(/[^/]+/[^/]+(?:/builds(?:/[\d]+)?|/cc\.xml)?)$)
set(:setup) { ActiveRecord::Base.logger = Travis.logger }
after do
p not_found?
force_redirect("/repositories#{$1}") if response.status == 404 && version == 'v1' && request.path =~ V1_REPO_URL
end
private
def force_redirect(path)
response.body = ''
response['Content-Length'] = '0'
response['Content-Type'] = ''
redirect(path)
end
def version
API.version(request.accept.join)
end
end
end
end

View File

@ -1,8 +1,5 @@
module Travis::Api::App::Responders
class Json < Base
ACCEPT_VERSION = /vnd\.travis-ci\.(\d+)\+/
DEFAULT_VERSION = 'v2'
def apply?
options[:format] == 'json' && !resource.is_a?(String)
end
@ -22,7 +19,7 @@ module Travis::Api::App::Responders
end
def version
request.accept.join =~ ACCEPT_VERSION && "v#{$1}" || DEFAULT_VERSION
API.version(request.accept.join)
end
end
end

View File

@ -31,14 +31,14 @@ describe 'Repos' do
response.should deliver_json_for(Repository.by_slug('svenfuchs/minimal').first, version: 'v1')
end
xit 'GET /svenfuchs/minimal' do
it 'GET /svenfuchs/minimal' do
response = get '/svenfuchs/minimal', {}, headers
response.should deliver_json_for(Repository.by_slug('svenfuchs/minimal').first, version: 'v1')
response.should redirect_to('/repositories/svenfuchs/minimal')
end
xit 'GET /svenfuchs/minimal/cc.xml' do # TODO wat.
it 'GET /svenfuchs/minimal/cc.xml' do
response = get '/svenfuchs/minimal/cc.xml'
response.should deliver_xml_for()
response.should redirect_to('/repositories/svenfuchs/minimal/cc.xml')
end
describe 'GET /svenfuchs/minimal.png' do

View File

@ -10,44 +10,7 @@ require 'multi_json'
require 'travis/api/app'
require 'travis/testing/scenario'
require 'travis/testing/factories'
RSpec::Matchers.define :deliver_json_for do |resource, options = {}|
match do |response|
actual = parse(response.body)
expected = Travis::Api.data(resource, options)
failure_message_for_should do
"expected\n\n#{actual}\n\nto equal\n\n#{expected}"
end
actual == expected
end
def parse(body)
MultiJson.decode(body)
end
end
RSpec::Matchers.define :deliver_result_image_for do |name|
match do |response|
actual = files.detect do |(name, content)|
response.body.force_encoding('ascii') == content.force_encoding('ascii') # TODO ummmmmmmm?
end
actual = actual && actual[0]
failure_message_for_should do
"expected #{actual.inspect} to equal #{name.inspect}"
end
actual == name
end
def files
files = Hash[*Dir['public/images/result/*.png'].map do |file|
[File.basename(file, '.png'), File.read(file)]
end.flatten]
end
end
require 'support/matchers'
Travis.logger = Logger.new(StringIO.new)
Travis::Api::App.setup

62
spec/support/matchers.rb Normal file
View File

@ -0,0 +1,62 @@
# TODO move to travis-core?
RSpec::Matchers.define :deliver_json_for do |resource, options = {}|
match do |response|
if response.status == 200
actual = parse(response.body)
expected = Travis::Api.data(resource, options)
failure_message_for_should do
"expected\n\n#{actual}\n\nto equal\n\n#{expected}"
end
actual == expected
else
failure_message_for_should do
"expected the request to be successful (200) but was #{response.status}"
end
false
end
end
def parse(body)
MultiJson.decode(body)
end
end
RSpec::Matchers.define :deliver_result_image_for do |name|
match do |response|
actual = files.detect do |(name, content)|
response.body.force_encoding('ascii') == content.force_encoding('ascii') # TODO ummmmmmmm?
end
actual = actual && actual[0]
failure_message_for_should do
"expected #{actual.inspect} to equal #{name.inspect}"
end
actual == name
end
def files
files = Hash[*Dir['public/images/result/*.png'].map do |file|
[File.basename(file, '.png'), File.read(file)]
end.flatten]
end
end
RSpec::Matchers.define :redirect_to do |expected|
match do |response|
actual = response.headers['location'].to_s.sub('http://example.org', '')
failure_message_for_should do
"expected to be redirect to #{expected} but was not. status: #{response.status}, location: #{actual}"
end
failure_message_for_should_not do
"expected not to be redirect to #{expected} but was."
end
actual == expected
end
end