<commit_before>#This class parses and handels post-multipart requests.
class Knjappserver::Httpsession::Post_multipart
  attr_reader :return
  
  def initialize(args)
    @args = args
    boundary_regexp = /\A--#{@args["boundary"]}(--)?#{@args["crlf"]}\z/
    @return = {}
    @data = nil
    @mode = nil
    @headers = {}
    
    @args["io"].each do |line|
      if boundary_regexp =~ line
        #Finish the data we were writing.
        self.finish_data if @data
        
        @data = ""
        @mode = "headers"
      elsif @mode == "headers"
        if match = line.match(/^(.+?):\s+(.+)#{@args["crlf"]}$/)
          @headers[match[1].to_s.downcase] = match[2]
        elsif line == @args["crlf"]
          @mode = "body"
        else
          raise "Could not match header from: '#{line}'."
        end
      elsif @mode == "body"
        @data << line
      else
        raise "Invalid mode: '#{@mode}'."
      end
    end
    
    self.finish_data if @data and @data.to_s.length > 0
    
    @data = nil
    @headers = nil
    @mode = nil
    @args = nil
  end
  
  #Add the current treated data to the return-hash.
  def finish_data
    @data.chop!
    name = nil
    
    disp = @headers["content-disposition"]
    raise "No 'content-disposition' was given." if !disp
    
    match_name = disp.match(/name=\"(.+?)\"/)
    raise "Could not match name." if !match_name
    
    match_fname = disp.match(/filename=\"(.+?)\"/)
    
    if match_fname
      obj = Knjappserver::Httpsession::Post_multipart::File_upload.new(
        "fname" => match_fname[1],
        "headers" => @headers,
        "data" => @data
      )
      @return[match_name[1]] = obj
      @data = nil
      @headers = {}
      @mode = nil
    else
      @return[match_name[1]] = @data
      @data = nil
      @headers = {}
      @mode = nil
    end
  end
end

#This is the actual returned object for fileuploads. It is able to do various user-friendly things like save the content to a given path, return the filename, returns the content to a string and more.
class Knjappserver::Httpsession::Post_multipart::File_upload
  def initialize(args)
    @args = args
  end
  
  #Returns the size of the upload.
  def size
    return @args["data"].length
  end
  
  #Returns the size of the fileupload.
  def length
    return @args["data"].length
  end
  
  #Returns the filename given for the fileupload.
  def filename
    return @args["fname"]
  end
  
  #Returns the headers given for the fileupload. Type and more should be here.
  def headers
    return @args["headers"]
  end
  
  #Returns the content of the file-upload as a string.
  def to_s
    return @args["data"]
  end
  
  #Saves the content of the fileupload to a given path.
  def save_to(filepath)
    File.open(filepath, "w") do |fp|
      fp.write(self.to_s)
    end
  end
  
  #This methods prevents the object from being converted to JSON. This can make some serious bugs.
  def to_json(*args)
    raise "File_upload-objects should not be converted to json."
  end
end<commit_msg>Fixed bug when posting multipart-forms with [] increment names.<commit_after>#This class parses and handels post-multipart requests.
class Knjappserver::Httpsession::Post_multipart
  attr_reader :return
  
  def initialize(args)
    @args = args
    boundary_regexp = /\A--#{@args["boundary"]}(--)?#{@args["crlf"]}\z/
    @return = {}
    @data = nil
    @mode = nil
    @headers = {}
    @counts = {}
    
    @args["io"].each do |line|
      if boundary_regexp =~ line
        #Finish the data we were writing.
        self.finish_data if @data
        
        @data = ""
        @mode = "headers"
      elsif @mode == "headers"
        if match = line.match(/^(.+?):\s+(.+)#{@args["crlf"]}$/)
          @headers[match[1].to_s.downcase] = match[2]
        elsif line == @args["crlf"]
          @mode = "body"
        else
          raise "Could not match header from: '#{line}'."
        end
      elsif @mode == "body"
        @data << line
      else
        raise "Invalid mode: '#{@mode}'."
      end
    end
    
    self.finish_data if @data and @data.to_s.length > 0
    
    @data = nil
    @headers = nil
    @mode = nil
    @args = nil
  end
  
  #Add the current treated data to the return-hash.
  def finish_data
    @data.chop!
    name = nil
    
    disp = @headers["content-disposition"]
    raise "No 'content-disposition' was given." if !disp
    
    
    #Figure out value-name in post-hash.
    match_name = disp.match(/name=\"(.+?)\"/)
    raise "Could not match name." if !match_name
    name = match_name[1]
    
    
    #Fix count with name if given as increamental [].
    if match = name.match(/^(.+)\[\]$/)
      if !@counts.key?(match[1])
        @counts[match[1]] = 0
      else
        @counts[match[1]] += 1
      end
      
      name = "#{match[1]}[#{@counts[match[1]]}]"
    end
    
    
    #Figure out actual filename.
    match_fname = disp.match(/filename=\"(.+?)\"/)
    
    if match_fname
      obj = Knjappserver::Httpsession::Post_multipart::File_upload.new(
        "fname" => match_fname[1],
        "headers" => @headers,
        "data" => @data
      )
      @return[name] = obj
      @data = nil
      @headers = {}
      @mode = nil
    else
      @return[name] = @data
      @data = nil
      @headers = {}
      @mode = nil
    end
  end
end

#This is the actual returned object for fileuploads. It is able to do various user-friendly things like save the content to a given path, return the filename, returns the content to a string and more.
class Knjappserver::Httpsession::Post_multipart::File_upload
  def initialize(args)
    @args = args
  end
  
  #Returns the size of the upload.
  def size
    return @args["data"].length
  end
  
  #Returns the size of the fileupload.
  def length
    return @args["data"].length
  end
  
  #Returns the filename given for the fileupload.
  def filename
    return @args["fname"]
  end
  
  #Returns the headers given for the fileupload. Type and more should be here.
  def headers
    return @args["headers"]
  end
  
  #Returns the content of the file-upload as a string.
  def to_s
    return @args["data"]
  end
  
  #Saves the content of the fileupload to a given path.
  def save_to(filepath)
    File.open(filepath, "w") do |fp|
      fp.write(self.to_s)
    end
  end
  
  #This methods prevents the object from being converted to JSON. This can make some serious bugs.
  def to_json(*args)
    raise "File_upload-objects should not be converted to json."
  end
end
{'fraction_non_alphanumeric': 0.12382854509141189, 'fraction_numerical': 0.002765401751421109, 'mean_word_length': 2.3112919633774163, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, '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': '2882625', 'n_tokens_mistral': 2137, 'n_tokens_neox': 2114, 'n_words': 652}