lib/contrast/agent/middleware.rb in contrast-agent-4.2.0 vs lib/contrast/agent/middleware.rb in contrast-agent-4.3.0

- old
+ new

@@ -77,11 +77,11 @@ # to the user up the Rack framework. def call env Contrast::Utils::HeapDumpUtil.run if AGENT.enabled? - Contrast::Agent::StaticAnalysis.catchup + handle_first_request call_with_agent(env) else app.call(env) end end @@ -89,20 +89,51 @@ private def setup_agent SETTINGS.reset_state + inform_deprecations + if CONFIG.invalid? AGENT.disable! logger.error('!!! CONFIG FILE IS INVALID - DISABLING CONTRAST AGENT !!!') elsif AGENT.disabled? logger.warn('Contrast disabled by configuration. Continuing without instrumentation.') else AGENT.enable! end end + # Some things have to wait until first request to happen, either because + # resolution is not complete or because the framework will preload + # classes, which confuses some of our instrumentation. + def handle_first_request + @_handle_first_request ||= begin + Contrast::Agent::StaticAnalysis.catchup + force_patching + true + end + end + + # TODO: RUBY-1090 remove this method and those it calls. + # + # These modules are auto-loaded by Rails, meaning they are defined at + # startup, but that they don't actually exist. We account for this in + # most cases by using the ClassUtil.truly_defined? method, but it appears + # to fail for these Modules. In the short term, we can forcing a re-patch + # so that their dead zones apply. + def force_patching + force_patch(ActionDispatch::FileHandler) if defined?(ActionDispatch::FileHandler) + force_patch(ActionDispatch::Http::MimeNegotiation) if defined?(ActionDispatch::Http::MimeNegotiation) + force_patch(ActionView::Template) if defined?(ActionView::Template) + end + + def force_patch mod + data = Contrast::Agent::ModuleData.new(mod) + Contrast::Agent::Patching::Policy::Patcher.send(:patch_into_module, data, true) + end + # This is where we process each request we intercept as a middleware. We make the request context # available globally so that it can be accessed from anywhere. A RequestHandler object is made # for each request, which handles prefilter and postfilter operations. def call_with_agent env Contrast::Agent.thread_watcher.ensure_running? @@ -170,9 +201,27 @@ [exception_control[:status], {}, [exception_control[:message]]] else logger.debug('Re-throwing original error', exception) raise exception end + end + + # As we deprecate support to prepare to remove dead code, we need to + # inform our users still relying on the now deprecated and soon to be + # removed functionality. This method handles doing that by leveraging the + # standard Kernel#warn approach + def inform_deprecations + # Ruby 2.5 is currently in security maintenance, meaning int is only + # receiving updates for security issues. It will move to eol on 31 + # March 2021. As such, we can remove support for it in Q2. We'll begin + # the deprecation warnings now so that customers have time to reach out + # if they'll be impacted. + # TODO: RUBY-715 remove this part of the method, leaving it empty if + # there are no other deprecations, when we drop 2.5 support. + return unless RUBY_VERSION < '2.6.0' + + Kernel.warn('[Contrast Security] [DEPRECATION] Support for Ruby 2.5 will be removed in April 2021. '\ + 'Please contact Customer Support prior if you require continued support.') end end end end