X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/7e5cbe87ed37f9cba8224fa4049047d7f981f66a..8f57efe850bf9805d9bfb073d16d4cf1d06882f5:/app/controllers/api_controller.rb?ds=sidebyside diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index a8067a493..7e1b06a8d 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -143,4 +143,63 @@ class ApiController < ApplicationController end end end + + def api_call_handle_error + yield + rescue ActionController::UnknownFormat + head :not_acceptable + rescue ActiveRecord::RecordNotFound => e + head :not_found + rescue LibXML::XML::Error, ArgumentError => e + report_error e.message, :bad_request + rescue ActiveRecord::RecordInvalid => e + message = "#{e.record.class} #{e.record.id}: " + e.record.errors.each { |error| message << "#{error.attribute}: #{error.message} (#{e.record[error.attribute].inspect})" } + report_error message, :bad_request + rescue OSM::APIError => e + report_error e.message, e.status + rescue AbstractController::ActionNotFound => e + raise + rescue StandardError => e + logger.info("API threw unexpected #{e.class} exception: #{e.message}") + e.backtrace.each { |l| logger.info(l) } + report_error "#{e.class}: #{e.message}", :internal_server_error + end + + ## + # asserts that the request method is the +method+ given as a parameter + # or raises a suitable error. +method+ should be a symbol, e.g: :put or :get. + def assert_method(method) + ok = request.send(:"#{method.to_s.downcase}?") + raise OSM::APIBadMethodError, method unless ok + end + + ## + # wrap an api call in a timeout + def api_call_timeout(&block) + Timeout.timeout(Settings.api_timeout, Timeout::Error, &block) + rescue ActionView::Template::Error => e + e = e.cause + + if e.is_a?(Timeout::Error) || + (e.is_a?(ActiveRecord::StatementInvalid) && e.message.include?("execution expired")) + ActiveRecord::Base.connection.raw_connection.cancel + raise OSM::APITimeoutError + else + raise + end + rescue Timeout::Error + ActiveRecord::Base.connection.raw_connection.cancel + raise OSM::APITimeoutError + end + + ## + # check the api change rate limit + def check_rate_limit(new_changes = 1) + max_changes = ActiveRecord::Base.connection.select_value( + "SELECT api_rate_limit($1)", "api_rate_limit", [current_user.id] + ) + + raise OSM::APIRateLimitExceeded if new_changes > max_changes + end end