This file is indexed.

/usr/lib/ruby/vendor_ruby/merb-core/dispatch/request_parsers.rb is in ruby-merb-core 1.1.3+dfsg-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
module Merb
  module Parse
  
    # ==== Parameters
    # query_string<String>:: The query string.
    # delimiter<String>:: The query string divider. Defaults to "&".
    # preserve_order<Boolean>:: Preserve order of args. Defaults to false.
    #
    # ==== Returns
    # Mash:: The parsed query string (Dictionary if preserve_order is set).
    #
    # ==== Examples
    #   Merb::Parse.query("bar=nik&post[body]=heya")
    #     # => { :bar => "nik", :post => { :body => "heya" } }
    #
    # :api: plugin
    def self.query(query_string, delimiter = '&;', preserve_order = false)
      query = preserve_order ? Dictionary.new : {}
      for pair in (query_string || '').split(/[#{delimiter}] */n)
        key, value = unescape(pair).split('=',2)
        next if key.nil?
        if key.include?('[')
          normalize_params(query, key, value)
        else
          query[key] = value
        end
      end
      preserve_order ? query : query.to_mash
    end

    NAME_REGEX         = /Content-Disposition:.* name="?([^\";]*)"?/ni.freeze
    CONTENT_TYPE_REGEX = /Content-Type: (.*)\r\n/ni.freeze
    FILENAME_REGEX     = /Content-Disposition:.* filename="?([^\";]*)"?/ni.freeze
    CRLF               = "\r\n".freeze
    EOL                = CRLF
  
    # ==== Parameters
    # request<IO>:: The raw request.
    # boundary<String>:: The boundary string.
    # content_length<Fixnum>:: The length of the content.
    #
    # ==== Raises
    # ControllerExceptions::MultiPartParseError:: Failed to parse request.
    #
    # ==== Returns
    # Hash:: The parsed request.
    #
    # :api: plugin
    def self.multipart(request, boundary, content_length)
      boundary = "--#{boundary}"
      paramhsh = {}
      buf      = ""
      input    = request
      input.binmode if defined? input.binmode
      boundary_size = boundary.size + EOL.size
      bufsize       = 16384
      content_length -= boundary_size
      key_memo = []
      # status is boundary delimiter line
      status = input.read(boundary_size)
      return {} if status == nil || status.empty?
      raise ControllerExceptions::MultiPartParseError, "bad content body:\n'#{status}' should == '#{boundary + EOL}'"  unless status == boundary + EOL

      rx = /(?:#{EOL})?#{Regexp.quote(boundary)}(#{EOL}|--)/n
      loop {
        head      = nil
        body      = ''
        filename  = content_type = name = nil
        read_size = 0
        until head && buf =~ rx
          i = buf.index("\r\n\r\n")
          if( i == nil && read_size == 0 && content_length == 0 )
            content_length = -1
            break
          end
          if !head && i
            head = buf.slice!(0, i+2) # First \r\n
            buf.slice!(0, 2)          # Second \r\n

            # String#[] with 2nd arg here is returning
            # a group from match data
            filename     = head[FILENAME_REGEX, 1]
            content_type = head[CONTENT_TYPE_REGEX, 1]
            name         = head[NAME_REGEX, 1]

            if filename && !filename.empty?
              body = Tempfile.new(:Merb)
              body.binmode if defined? body.binmode
            end
            next
          end

          # Save the read body part.
          if head && (boundary_size+4 < buf.size)
            body << buf.slice!(0, buf.size - (boundary_size+4))
          end

          read_size = bufsize < content_length ? bufsize : content_length
          if( read_size > 0 )
            c = input.read(read_size)
            raise ControllerExceptions::MultiPartParseError, "bad content body"  if c.nil? || c.empty?
            buf << c
            content_length -= c.size
          end
        end

        # Save the rest.
        if i = buf.index(rx)
          # correct value of i for some edge cases
          if (i > 2) && (j = buf.index(rx, i-2)) && (j < i)
             i = j
           end
          body << buf.slice!(0, i)
          buf.slice!(0, boundary_size+2)

          content_length = -1  if $1 == "--"
        end

        if filename && !filename.empty?
          body.rewind
          data = {
            :filename => File.basename(filename),
            :content_type => content_type,
            :tempfile => body,
            :size => File.size(body.path)
          }
        else
          data = body
        end

        unless key_memo.include?(name) && name !~ /\[\]/ 
          paramhsh = normalize_params(paramhsh,name,data) 
        end

        # Prevent from double processing files but process other params
        key_memo << name if filename && !filename.empty?

        break  if buf.empty? || content_length == -1
      }

      paramhsh
    end

    # ==== Parameters
    # value<Array, Hash, Dictionary ~to_s>:: The value for the query string.
    # prefix<~to_s>:: The prefix to add to the query string keys.
    #
    # ==== Returns
    # String:: The query string.
    #
    # ==== Alternatives
    # If the value is a string, the prefix will be used as the key.
    #
    # ==== Examples
    #   params_to_query_string(10, "page")
    #     # => "page=10"
    #   params_to_query_string({ :page => 10, :word => "ruby" })
    #     # => "page=10&word=ruby"
    #   params_to_query_string({ :page => 10, :word => "ruby" }, "search")
    #     # => "search[page]=10&search[word]=ruby"
    #   params_to_query_string([ "ice-cream", "cake" ], "shopping_list")
    #     # => "shopping_list[]=ice-cream&shopping_list[]=cake"
    #
    # :api: plugin
    def self.params_to_query_string(value, prefix = nil)
      case value
      when Array
        value.map { |v|
          params_to_query_string(v, "#{prefix}[]")
        } * "&"
      when Hash, Dictionary
        value.map { |k, v|
          params_to_query_string(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
        } * "&"
      else
        "#{prefix}=#{escape(value)}"
      end
    end

    # ==== Parameters
    # s<String>:: String to URL escape.
    #
    # ==== returns
    # String:: The escaped string.
    #
    # :api: public
    def self.escape(s)
      s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
        '%'+$1.unpack('H2'*$1.size).join('%').upcase
      }.tr(' ', '+')
    end

    # ==== Parameter
    # s<String>:: String to URL unescape.
    # encoding<String>:: Encoding which we force to return. Only for 
    #                    Ruby 1.9. If encoding is not passed it defaults
    #                    to Encoding.default_internal. When this is nil
    #                    (default) no encoding forcing is done.
    #
    # ==== returns
    # String:: The unescaped string.
    #
    # :api: public
    def self.unescape(s, encoding = nil)
      s = s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
        [$1.delete('%')].pack('H*')
      }
      if RUBY_VERSION >= '1.9'
        encoding ||= Encoding.default_internal
        s.force_encoding(encoding) if encoding
      end
      s
    end

    # ==== Parameters
    # s<String>:: String to XML escape.
    #
    # ==== returns
    # String:: The escaped string.
    #
    # :api: public
    def self.escape_xml(s)
      Erubis::XmlHelper.escape_xml(s)
    end

    private

    # Converts a query string snippet to a hash and adds it to existing
    # parameters.
    #
    # ==== Parameters
    # parms<Hash>:: Parameters to add the normalized parameters to.
    # name<String>:: The key of the parameter to normalize.
    # val<String>:: The value of the parameter.
    #
    # ==== Returns
    # Hash:: Normalized parameters
    #
    # :api: private
    def self.normalize_params(parms, name, val=nil)
      name =~ %r([\[\]]*([^\[\]]+)\]*)
      key = $1 || ''
      after = $' || ''

      if after == ""
        parms[key] = val
      elsif after == "[]"
        (parms[key] ||= []) << val
      elsif after =~ %r(^\[\]\[([^\[\]]+)\]$)
        child_key = $1
        parms[key] ||= []
        if parms[key].last.is_a?(Hash) && !parms[key].last.key?(child_key)
          parms[key].last.update(child_key => val)
        else
          parms[key] << { child_key => val }
        end
      else
        parms[key] ||= {}
        parms[key] = normalize_params(parms[key], after, val)
      end
      parms
    end  
  
  end
end