CGI and multipart data

Discussion in 'Ruby' started by Martin Hart, Feb 26, 2004.

  1. Martin Hart

    Martin Hart Guest

    Hi all,

    I have a single HTML form which contains simple text controls as well as file
    upload controls. I had assumed that the CGI library would return me items of
    type String for the text boxes and items of type Tempfile for the file upload
    boxes....

    However, it appears (after searching the archives) that StringIO is used
    instead of Tempfile on ruby 1.8 (in some cases and not others?), and that as
    soon as you specify an enctype of multipart you never? receive Strings but
    always receive either Tempfile or StringIO.

    This is what i really want from the CGI library:
    * CGI returns *everything* as a string except for file uploads - which are
    returned as Tempfiles

    Assuming that I cannot have that :) can somebody in the know please tell me
    (or point me to some documentation)...

    1. how can I tell whether or not the supplied parameter was a file upload or
    simple text that has been passed to me as a Tempfile/StringIO? At the moment
    I don't know whether to copy the file or not - because I don't know if it is
    a valid file or just another parameter.

    2. do hidden controls work with multi-part forms? there is some discussion of
    them not working on the mailing list dating back to last November but I don't
    know if that has been fixed or not. My limited testing here indicates that
    hidden parameters are ignored on multipart forms?

    3. why are all values expressed as Tempfile/StringIO when using a multipart
    form? Why not just have the file uploads as tempfiles?

    4. how does the CGI library determine whether or not to switch between
    Tempfile/StringIO

    5. do I have to specifically close the IO object (assuming that one is
    returned?) - or perhaps I do not have to close the StringIO but I do have to
    close the Tempfile?

    6. are all of the form parameters in different tempfiles or are they all in
    one? Say i close the file after reading 1 argument ... does this mean that I
    cannot read any more?

    Thanks for any help you can give me - I am pretty stuck on this. If I get
    code working with StringIO objects it seems to break when I submit large
    files, and if I get code working with Tempfile it seems to break when I
    submit small files :)

    Cheers,
    Martin


    --
    Martin Hart
    Arnclan Limited
    53 Union Street
    Dunstable, Beds
    LU6 1EX
    http://www.arnclanit.com
    Martin Hart, Feb 26, 2004
    #1
    1. Advertising

  2. Martin Hart wrote:

    >Hi all,
    >
    >I have a single HTML form which contains simple text controls as well as file
    >upload controls. I had assumed that the CGI library would return me items of
    >type String for the text boxes and items of type Tempfile for the file upload
    >boxes....
    >
    >However, it appears (after searching the archives) that StringIO is used
    >instead of Tempfile on ruby 1.8 (in some cases and not others?), and that as
    >soon as you specify an enctype of multipart you never? receive Strings but
    >always receive either Tempfile or StringIO.
    >
    >This is what i really want from the CGI library:
    >* CGI returns *everything* as a string except for file uploads - which are
    >returned as Tempfiles
    >
    >Assuming that I cannot have that :) can somebody in the know please tell me
    >(or point me to some documentation)...
    >
    >1. how can I tell whether or not the supplied parameter was a file upload or
    >simple text that has been passed to me as a Tempfile/StringIO? At the moment
    >I don't know whether to copy the file or not - because I don't know if it is
    >a valid file or just another parameter.
    >
    >

    If it is just posted, its text. If you use enctype=multipart/form-data
    then all will be files.
    If you use the second, use $cgi['your_form_item'][0].read to get the
    text value.

    For example:
    oOverwrite = $cgi['overwrite'][0] #this is a checkbox
    if oOverwrite
    overwrite = oOverwrite.read.chomp #i'm reading it's value
    if overwrite == 'on' then bOverwrite = true end
    end

    Notice i never close the tmp file. Never thot about it ;o)

    >2. do hidden controls work with multi-part forms? there is some discussion of
    >them not working on the mailing list dating back to last November but I don't
    >know if that has been fixed or not. My limited testing here indicates that
    >hidden parameters are ignored on multipart forms?
    >
    >
    >

    Yes. You'll need to access them as if they were a file - like above.

    >3. why are all values expressed as Tempfile/StringIO when using a multipart
    >form? Why not just have the file uploads as tempfiles?
    >
    >
    >

    I've not used StringIO

    >4. how does the CGI library determine whether or not to switch between
    >Tempfile/StringIO
    >
    >
    >

    Dont know

    >5. do I have to specifically close the IO object (assuming that one is
    >returned?) - or perhaps I do not have to close the StringIO but I do have to
    >close the Tempfile?
    >
    >
    >

    Hum, dont know.I've never closed them

    >6. are all of the form parameters in different tempfiles or are they all in
    >one? Say i close the file after reading 1 argument ... does this mean that I
    >cannot read any more?
    >
    >
    >

    I _think_ they are individual files.

    Somthing to note : IE sends the whole path for the file name. NS(1.6)
    only send the name.

    CGI can be kind of counter intuitive - but it will work!

    :p
    Paul Vudmaska, Feb 26, 2004
    #2
    1. Advertising

  3. Martin Hart wrote:

    >Hi all,
    >
    >I have a single HTML form which contains simple text controls as well as file
    >upload controls. I had assumed that the CGI library would return me items of
    >type String for the text boxes and items of type Tempfile for the file upload
    >boxes....
    >
    >However, it appears (after searching the archives) that StringIO is used
    >instead of Tempfile on ruby 1.8 (in some cases and not others?), and that as
    >soon as you specify an enctype of multipart you never? receive Strings but
    >always receive either Tempfile or StringIO.
    >
    >This is what i really want from the CGI library:
    >* CGI returns *everything* as a string except for file uploads - which are
    >returned as Tempfiles
    >
    >Assuming that I cannot have that :) can somebody in the know please tell me
    >(or point me to some documentation)...
    >
    >1. how can I tell whether or not the supplied parameter was a file upload or
    >simple text that has been passed to me as a Tempfile/StringIO? At the moment
    >I don't know whether to copy the file or not - because I don't know if it is
    >a valid file or just another parameter.
    >
    >2. do hidden controls work with multi-part forms? there is some discussion of
    >them not working on the mailing list dating back to last November but I don't
    >know if that has been fixed or not. My limited testing here indicates that
    >hidden parameters are ignored on multipart forms?
    >
    >3. why are all values expressed as Tempfile/StringIO when using a multipart
    >form? Why not just have the file uploads as tempfiles?
    >
    >4. how does the CGI library determine whether or not to switch between
    >Tempfile/StringIO
    >
    >5. do I have to specifically close the IO object (assuming that one is
    >returned?) - or perhaps I do not have to close the StringIO but I do have to
    >close the Tempfile?
    >
    >6. are all of the form parameters in different tempfiles or are they all in
    >one? Say i close the file after reading 1 argument ... does this mean that I
    >cannot read any more?
    >
    >Thanks for any help you can give me - I am pretty stuck on this. If I get
    >code working with StringIO objects it seems to break when I submit large
    >files, and if I get code working with Tempfile it seems to break when I
    >submit small files :)
    >
    >Cheers,
    >Martin
    >
    >
    >
    >

    Here is the code that i use. Prob not the best but has worked for me so far.

    class Upload
    #{{{ -----------------------Uploads file to server from html
    form--------------------------

    #max size of file in bytes
    MAX_SIZE = 100000

    #where the file goes / MUST HAVE WRITE PRIVS HERE
    PATH = "/home/paul/web/"

    #how many file inputs - you can upload multiple files at once
    FILE_COUNT = 3

    #what file types do we allow?
    CONTENT_TYPES= ['image/jpg','image/jpeg','image/gif','image/png']




    def initialize

    #how are things going?
    @status = []

    if $form.isPost

    post

    print @status.join('<br/>')

    form

    else


    form


    end

    end
    def form
    #{{{

    puts '<form method="post" enctype="multipart/form-data">'

    FILE_COUNT.times do

    puts '<p/><input type="file" name="myfile">'

    end

    puts '<p/><input type=hidden name=upl value="upload">'
    puts '<br/><input type=checkbox name="overwrite"/>Overwrite?'
    puts '<br/><input type="submit">'
    puts '</form>'

    end#}}}


    def post
    #{{{


    oOverwrite = $cgi['overwrite'][0]
    bOverwrite = false
    overwrite = ''

    if oOverwrite
    overwrite = oOverwrite.read.chomp
    if overwrite == 'on' then bOverwrite = true end
    end

    $cgi['myfile'].each do |incoming|

    if incoming.size == 0

    @status<< "Ignoring empty field"
    next

    end

    if incoming.size > MAX_SIZE

    @status<< "Data too large for
    #{incoming.original_filename}(#{incoming.size} > #{MAX_SIZE})"
    next

    end

    #need to strip :)...trailing space...ouch
    if not CONTENT_TYPES.include? incoming.content_type.strip

    @status<< "Type not allowed(type =
    #{incoming.content_type}) allowed content = #{CONTENT_TYPES.join(' | ')}"
    next

    end

    #puts incoming.filename
    # all should be ok to upload

    sfilename = incoming.original_filename.untaint

    #see if name has whacks...ie?
    rdash = sfilename.rindex('\\')
    if rdash
    sfilename = sfilename[rdash+1,sfilename.length]
    end

    #physical path
    path = PATH + $Domain + '/img/' + sfilename


    if File.exist? path
    if bOverwrite
    File.delete path
    else
    @status<< "File already exists
    (#{incoming.original_filename})"
    next
    end
    end

    #write to file
    file = File.new(path.untaint,'w')
    file << incoming.read
    file.close

    #path to link from web
    httpPath = "http://#{$Domain}/img/#{sfilename}"

    @status<< "Completed upload of <a target=_blank
    href='#{httpPath}'>#{httpPath}</a>"
    end

    end#}}}

    end#}}}
    Upload.new
    Paul Vudmaska, Feb 26, 2004
    #3
  4. Martin Hart

    Martin Hart Guest

    On Thursday 26 February 2004 21:05, Paul Vudmaska wrote:
    > Martin Hart wrote:
    > >1. how can I tell whether or not the supplied parameter was a file upload
    > > or simple text that has been passed to me as a Tempfile/StringIO?

    >
    > If it is just posted, its text. If you use enctype=multipart/form-data
    > then all will be files.
    > If you use the second, use $cgi['your_form_item'][0].read to get the
    > text value.


    that's not quite what I meant... On a multipart form, is there a way to
    determine whether or not the value at $cgi["fred"] represents an uploaded
    file or just some text that was entered into an input control?

    > >2. do hidden controls work with multi-part forms?

    >
    > Yes. You'll need to access them as if they were a file - like above.
    >


    ok I'll have to try this again - my previous tests led me to believe that
    $cgi["fish"] (where fish was a hidden control) returned me nil whatever the
    value of the control was. I'll retest this.

    > >3. why are all values expressed as Tempfile/StringIO when using a
    > > multipart form? Why not just have the file uploads as tempfiles?

    >
    > I've not used StringIO
    >


    I didn't think it was optional - is there a way to turn it off so that only
    Tempfiles are used?


    Ruby-talk #19664 contains a patch that seems to offer what I want (i.e.
    representing only file uploads as objects of class Tempfile). However that
    message is from Aug 2001 and things have moved on since then...

    Can I ask if that patch was ever incorporated and if not why it was not
    suitable?

    It seems to me to be illogical and inefficient (assuming we have to create a
    load of tempfiles) to present all multipart form values as IO objects -
    surely it is better to just present the values that contain actual file
    uploads as IO objects?

    Cheers,
    Martin
    Martin Hart, Feb 26, 2004
    #4
  5. Martin Hart wrote:

    >On Thursday 26 February 2004 21:05, Paul Vudmaska wrote:
    >
    >
    >>Martin Hart wrote:
    >>
    >>
    >>>1. how can I tell whether or not the supplied parameter was a file upload
    >>>or simple text that has been passed to me as a Tempfile/StringIO?
    >>>
    >>>

    >>If it is just posted, its text. If you use enctype=multipart/form-data
    >>then all will be files.
    >>If you use the second, use $cgi['your_form_item'][0].read to get the
    >>text value.
    >>
    >>

    >
    >that's not quite what I meant... On a multipart form, is there a way to
    >determine whether or not the value at $cgi["fred"] represents an uploaded
    >file or just some text that was entered into an input control?
    >
    >
    >

    No, not as far as i know(which is not very far!!)

    >>>2. do hidden controls work with multi-part forms?
    >>>
    >>>

    >>Yes. You'll need to access them as if they were a file - like above.
    >>
    >>
    >>

    >ok I'll have to try this again - my previous tests led me to believe that
    >
    >
    >$cgi["fish"] (where fish was a hidden control) returned me nil whatever the
    >value of the control was. I'll retest this.
    >
    >

    They seem to work. I tested it.

    >
    >
    >>>3. why are all values expressed as Tempfile/StringIO when using a
    >>>multipart form? Why not just have the file uploads as tempfiles?
    >>>
    >>>

    >>I've not used StringIO
    >>
    >>
    >>

    Sorry, i dont know!

    >I didn't think it was optional - is there a way to turn it off so that only
    >Tempfiles are used?
    >
    >
    >Ruby-talk #19664 contains a patch that seems to offer what I want (i.e.
    >representing only file uploads as objects of class Tempfile). However that
    >message is from Aug 2001 and things have moved on since then...
    >
    >
    >

    The version I use (on my host) is 1.6 or so

    >Can I ask if that patch was ever incorporated and if not why it was not
    >suitable?
    >
    >
    >
    >It seems to me to be illogical and inefficient (assuming we have to create a
    >load of tempfiles) to present all multipart form values as IO objects -
    >surely it is better to just present the values that contain actual file
    >uploads as IO objects?
    >
    >Cheers,
    >Martin
    >
    >
    >
    >

    Seems like a good questions but I honestly dont know.

    When things are sent with multipart/form-data the items are actually
    sent as a sort of binary form(to support say,gif files). And it is the
    responsibility of the server side code to disect it.

    So, the fields are either all binary or all text.

    But hey, i'm pretty new so keep that in mind :)
    Paul
    Paul Vudmaska, Feb 26, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Simon Callan

    CGI and multipart/related data

    Simon Callan, Sep 2, 2004, in forum: Perl
    Replies:
    2
    Views:
    695
    Simon Callan
    Sep 16, 2004
  2. Chris Curvey

    cgi and multipart/form-data?

    Chris Curvey, Mar 29, 2005, in forum: Python
    Replies:
    1
    Views:
    1,248
    Chris Curvey
    Mar 29, 2005
  3. Francis Hwang
    Replies:
    3
    Views:
    234
    Patrick May
    Sep 14, 2004
  4. Stefan Fischer
    Replies:
    2
    Views:
    262
    Stefan Fischer
    Feb 23, 2010
  5. Replies:
    1
    Views:
    399
Loading...

Share This Page