module HTTP::FormData class Parser # Creates a new parser which parses *io* with multipart boundary *boundary*. def initialize(io, boundary) @multipart = MIME::Multipart::Parser.new(io, boundary) end # Parses the next form-data part and yields field name, io, `FileMetadata`, # and raw headers. # # This method yields once instead of returning the values, because the IO # object yielded to the block is only valid while the block is executing. # The IO object will be closed as soon as the block returns. To store the # content of the body part for longer than the block, the IO must be read # into memory. # # ``` # require "http" # # form_data = "--aA40\r\nContent-Disposition: form-data; name=\"field1\"; filename=\"foo.txt\"; size=13\r\nContent-Type: text/plain\r\n\r\nfield data\r\n--aA40--" # parser = HTTP::FormData::Parser.new(IO::Memory.new(form_data), "aA40") # parser.next do |part| # part.name # => "field1" # part.body.gets_to_end # => "field data" # part.filename # => "foo.txt" # part.size # => 13 # part.headers["Content-Type"] # => "text/plain" # end # ``` def next(&) raise FormData::Error.new("Parser has already finished parsing") unless has_next? while @multipart.has_next? @multipart.next do |headers, io| yield HTTP::FormData::Part.new(headers, io) end end end # True if `#next` can be called legally. def has_next? : Bool @multipart.has_next? end end end