<commit_before># frozen_string_literal: true

require 'rack/show_exceptions'

module Sinatra
  # Sinatra::ShowExceptions catches all exceptions raised from the app it
  # wraps. It shows a useful backtrace with the sourcefile and clickable
  # context, the whole Rack environment and the request data.
  #
  # Be careful when you use this on public-facing sites as it could reveal
  # information helpful to attackers.
  class ShowExceptions < Rack::ShowExceptions
    @@eats_errors = Object.new
    def @@eats_errors.flush(*) end
    def @@eats_errors.puts(*) end

    def initialize(app)
      @app = app
    end

    def call(env)
      @app.call(env)
    rescue Exception => e
      errors, env["rack.errors"] = env["rack.errors"], @@eats_errors

      if prefers_plain_text?(env)
        content_type = "text/plain"
        body = dump_exception(e)
      else
        content_type = "text/html"
        body = pretty(env, e)
      end

      env["rack.errors"] = errors

      [
        500,
        {
          "Content-Type" => content_type,
          "Content-Length" => body.bytesize.to_s
        },
        [body]
      ]
    end

    # Pulled from Rack::ShowExceptions in order to override TEMPLATE.
    # If Rack provides another way to override, this could be removed
    # in the future.
    def pretty(env, exception)
      req = Rack::Request.new(env)

      # This double assignment is to prevent an "unused variable" warning on
      # Ruby 1.9.3.  Yes, it is dumb, but I don't like Ruby yelling at me.
      path = path = (req.script_name + req.path_info).squeeze("/")

      # This double assignment is to prevent an "unused variable" warning on
      # Ruby 1.9.3.  Yes, it is dumb, but I don't like Ruby yelling at me.
      frames = frames = exception.backtrace.map { |line|
        frame = OpenStruct.new
        if line =~ /(.*?):(\d+)(:in `(.*)')?/
          frame.filename = $1
          frame.lineno = $2.to_i
          frame.function = $4

          begin
            lineno = frame.lineno-1
            lines = ::File.readlines(frame.filename)
            frame.pre_context_lineno = [lineno-CONTEXT, 0].max
            frame.pre_context = lines[frame.pre_context_lineno...lineno]
            frame.context_line = lines[lineno].chomp
            frame.post_context_lineno = [lineno+CONTEXT, lines.size].min
            frame.post_context = lines[lineno+1..frame.post_context_lineno]
          rescue
          end

          frame
        else
          nil
        end
      }.compact

      TEMPLATE.result(binding)
    end

    private

    def bad_request?(e)
      Sinatra::BadRequest === e
    end

    def prefers_plain_text?(env)
      !(Request.new(env).preferred_type("text/plain","text/html") == "text/html") &&
      [/curl/].index { |item| item =~ env["HTTP_USER_AGENT"] }
    end

    def frame_class(frame)
      if frame.filename =~ %r{lib/sinatra.*\.rb}
        "framework"
      elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
            frame.filename =~ %r{/bin/(\w+)\z}
        "system"
      else
        "app"
      end
    end

TEMPLATE = ERB.new <<-HTML # :nodoc:
<!DOCTYPE html>
<html><commit_msg>Override TEMPLATE using method supplied by Rack::ShowExceptions<commit_after># frozen_string_literal: true

require 'rack/show_exceptions'

module Sinatra
  # Sinatra::ShowExceptions catches all exceptions raised from the app it
  # wraps. It shows a useful backtrace with the sourcefile and clickable
  # context, the whole Rack environment and the request data.
  #
  # Be careful when you use this on public-facing sites as it could reveal
  # information helpful to attackers.
  class ShowExceptions < Rack::ShowExceptions
    @@eats_errors = Object.new
    def @@eats_errors.flush(*) end
    def @@eats_errors.puts(*) end

    def initialize(app)
      @app = app
    end

    def call(env)
      @app.call(env)
    rescue Exception => e
      errors, env["rack.errors"] = env["rack.errors"], @@eats_errors

      if prefers_plain_text?(env)
        content_type = "text/plain"
        body = dump_exception(e)
      else
        content_type = "text/html"
        body = pretty(env, e)
      end

      env["rack.errors"] = errors

      [
        500,
        {
          "Content-Type" => content_type,
          "Content-Length" => body.bytesize.to_s
        },
        [body]
      ]
    end

    def template
      TEMPLATE
    end

    private

    def bad_request?(e)
      Sinatra::BadRequest === e
    end

    def prefers_plain_text?(env)
      !(Request.new(env).preferred_type("text/plain","text/html") == "text/html") &&
      [/curl/].index { |item| item =~ env["HTTP_USER_AGENT"] }
    end

    def frame_class(frame)
      if frame.filename =~ %r{lib/sinatra.*\.rb}
        "framework"
      elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
            frame.filename =~ %r{/bin/(\w+)\z}
        "system"
      else
        "app"
      end
    end

TEMPLATE = ERB.new <<-HTML # :nodoc:
<!DOCTYPE html>
<html>
{'fraction_non_alphanumeric': 0.1178115015974441, 'fraction_numerical': 0.003594249201277955, 'mean_word_length': 2.2674494455316374, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5084242', 'n_tokens_mistral': 1636, 'n_tokens_neox': 1568, 'n_words': 409}