sarah
2009-Jan-15 02:48 UTC
application/octet-stream from flash: binary data, not swfupload
Hello, I''m working on a rails app with a flash application in it, and the flash application posts binary data to the rails app, to create and upload an image. The image arrives from Flash with a Content-Type of "application/octet-stream", but by the time the image data hits the controller action, it is a string. I have googled and found numerous solutions for similar cases: getting the content_type of data uploaded from flash (generally via swfobject) and adjusting for when the content-type is application/octet-stream. But, these don''t work in my case -- I''m guessing that all those cases are for actually uploading files rather than transporting binary data. I do have mimetype_fu installed and attachment_fu hacks and the mime_type gem but none of those solutions work because the data it''s working on in the controller is a string, and doesn''t have a content_type method. All of these workarounds involve querying the data for its content_type and adjusting from there. Initially we thought "oh the form doesn''t have multipart set", but when I track the data in request.rb (the parse_multipart_form_parameters method), the data seems to be properly encoded with the correct form type: The flash developer and I have done a lot of searching and it may be that the data needs to be sent differently from Flash (encoded in a different format perhaps, as a few blog posts suggest). But on the Rails end, does anyone have any insight on why the data is being thrown out by the time it gets to the controller? And, more importantly, where I might intercept it so by the time it hits the controller it is still application/octet-stream? Below are some debug outputs if you want to see more details: 1. LOGGING from parse_multipart_form_parameters in request.rb. This is the incoming request from Flash. -- Wed Jan 14 19:22:03 -0600 2009: here in parse_multipart_form_parameters: body: #<StringIO:0x3f03ab8> ; boundary: iuxcwgdgqyluhwtavtkiwakxwlyxfkxs ; body_size: 65822 ; env: {"SERVER_NAME"=>"localhost", "HTTP_ENCTYPE"=>"multipart/form-data", "PATH_INFO"=>"/projects/13/elements/21/assets/130/visual_notes", "CONTENT_LENGTH"=>"65822", "HTTP_CONTENT_TYPE"=>"multipart/form-data; boundary=iuxcwgdgqyluhwtavtkiwakxwlyxfkxs", "HTTP_ACCEPT_ENCODING"=>"gzip,deflate", "HTTP_USER_AGENT"=>"Mozilla/ 5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.5) Gecko/ 2008120121 Firefox/3.0.5", "SCRIPT_NAME"=>"/", "SERVER_PROTOCOL"=>"HTTP/1.1", "HTTP_CACHE_CONTROL"=>"no-cache", "HTTP_ACCEPT_LANGUAGE"=>"en-us,en;q=0.5", "HTTP_HOST"=>"localhost: 3000", "REMOTE_ADDR"=>"127.0.0.1", "SERVER_SOFTWARE"=>"Mongrel 1.1.5", "HTTP_CONTENT_LENGTH"=>"65822", "HTTP_KEEP_ALIVE"=>"300", "REQUEST_PATH"=>"/projects/13/elements/21/assets/130/visual_notes", "CONTENT_TYPE"=>"multipart/form-data; boundary=iuxcwgdgqyluhwtavtkiwakxwlyxfkxs", "HTTP_REFERER"=>"http:// localhost:3000/movies/image_creator.swf", "HTTP_COOKIE"=>"last-visited- project=canvasband; _canvasband_session=BAh7CToMdXNlcl9pZGkMOgxjc3JmX2lkIiUyOTI3ZjJiMGJlMDhmNzMxMDZh %0AY2M4NjUyZGZmYWI5ZDoOcmV0dXJuX3RvMCIKZmxhc2hJQzonQWN0aW9uQ29u %0AdHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D-- dcc1e413220b4e43db3ab08a37cf67ff73f8ec6e; auth_token=; mingle_2_1_session_id=4292f420b98099b491c469a9bffab2ac", "HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,utf-8;q=0.7,*;q=0.7", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"/projects/13/elements/21/ assets/130/visual_notes", "SERVER_PORT"=>"3000", "GATEWAY_INTERFACE"=>"CGI/1.2", "HTTP_ACCEPT"=>"text/html,application/ xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "HTTP_CONNECTION"=>"keep- alive", "REQUEST_METHOD"=>"POST"} 2. A little later in read_multipart, I can see that the data has arrived in the application/octet-stream format: Content-Disposition: form-data; name="image_uploaded_data"; filename="1141922993.jpg" Content-Type: application/octet-stream 3. My controller action params Parameters: `"element_id"=>"21", "project_id"=>"13", "action"=>"create", "authenticity_token"=>"d72daa6709e28c9ed1b55566419e1e8bd714da11", "image_uploaded_data"=>"1141951886.jpg", "Upload"=>"Submit Query", "controller"=>"projects/elements/assets/visual_notes", "visual_note_created_by_id"=>"1", "asset_id"=>"130 4. Output when running a before_filter to before_filter do |controller| logger.info("CLASS: #{controller.params [:image_uploaded_data].class}") end CLASS: String Thanks, Sarah --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Peter De Berdt
2009-Jan-15 09:11 UTC
Re: application/octet-stream from flash: binary data, not swfupload
On 15 Jan 2009, at 03:48, sarah wrote:> I''m working on a rails app with a flash application in it, and the > flash application posts binary data to the rails app, to create and > upload an image. The image arrives from Flash with a Content-Type of > "application/octet-stream", but by the time the image data hits the > controller action, it is a string.That''s merely because of the filesize of the data you are sending. Everything below 16KB will be seen as StringIO, above it will be a TempFile. Attachment_fu has everything in place to handle it. Look at line 303 at http://github.com/technoweenie/attachment_fu/blob/743a95be0f01696530f558e7f4934cc7e57d3ab8/lib/technoweenie/attachment_fu.rb> I have googled and found numerous solutions for similar cases: getting > the content_type of data uploaded from flash (generally via swfobject) > and adjusting for when the content-type is application/octet-stream. > But, these don''t work in my case -- I''m guessing that all those cases > are for actually uploading files rather than transporting binary > data.Attachment_fu combined with mimetype_fu work perfectly for me with any data sent from Flash. Flash has no way to pass in the appropriate content type (simply said: it''s always application/octet-stream), but I can see in your controller that you have a filename available (xxxx.jpg). This should be enough for mimetype_fu to determine the content-type as "image/jpeg". Best regards Peter De Berdt --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
sarah
2009-Jan-15 18:55 UTC
Re: application/octet-stream from flash: binary data, not swfupload
Thanks for the reply, Peter. Unfortunately, this is not what is happening in my application. Are you uploading images or passing binary data created in Flash to Rails? What is happening for us is that I am able to get the content-type as "image/jpeg" using mimetype_fu, but that is as far as things go. If I then try to save that data in the controller (using attachment_fu), like so: image_params = {:uploaded_data => params[''image_uploaded_data'']} image = @visual_note.build_image(image_params.merge(:created_by => current_user)) if image.valid? #do stuff else #errors end I get validates_as_attachment errors: Content type can''t be blank; Size can''t be blank; Size is not included in the list; Filename can''t be blank *** When I use some attachment_fu_hacks that I found here: http://seventytwo.co.uk/posts/making-swfupload-and-rails-work-together: def uploaded_data=(file_data) return nil if file_data.nil? || file_data.size == 0 self.content_type = detect_mimetype(file_data) self.filename = file_data.original_filename if respond_to? (:filename) if file_data.is_a?(StringIO) file_data.rewind self.temp_data = file_data.read else self.temp_path = file_data.path end end def detect_mimetype(file_data) if file_data.content_type.strip == "application/octet-stream" return File.mime_type?(file_data.original_filename) else return file_data.content_type end end end Errors are thrown because file_data -- the string passed in through my params[:image_uploaded_data] from Flash does not respond to content_type or original_filename *** Am I missing something from the point where the I am receiving the data in the controller and getting it to attachment_fu? It doesn''t know it is application/octet-stream because it doesn''t respond to content-type at the controller level. Thanks, Sarah On Jan 15, 3:11 am, Peter De Berdt <peter.de.be...-LPO8gxj9N8aZIoH1IeqzKA@public.gmane.org> wrote:> On 15 Jan 2009, at 03:48, sarah wrote: > > > I''m working on a rails app with a flash application in it, and the > > flash application posts binary data to the rails app, to create and > > upload an image. The image arrives from Flash with a Content-Type of > > "application/octet-stream", but by the time the image data hits the > > controller action, it is a string. > > That''s merely because of the filesize of the data you are sending. > Everything below 16KB will be seen as StringIO, above it will be a > TempFile. Attachment_fu has everything in place to handle it. > > Look at line 303 athttp://github.com/technoweenie/attachment_fu/blob/743a95be0f01696530f... > > > I have googled and found numerous solutions for similar cases: getting > > the content_type of data uploaded from flash (generally via swfobject) > > and adjusting for when the content-type is application/octet-stream. > > But, these don''t work in my case -- I''m guessing that all those cases > > are for actually uploading files rather than transporting binary > > data. > > Attachment_fu combined with mimetype_fu work perfectly for me with any > data sent from Flash. Flash has no way to pass in the appropriate > content type (simply said: it''s always application/octet-stream), but > I can see in your controller that you have a filename available > (xxxx.jpg). This should be enough for mimetype_fu to determine the > content-type as "image/jpeg". > > Best regards > > Peter De Berdt--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Peter De Berdt
2009-Jan-15 23:06 UTC
Re: application/octet-stream from flash: binary data, not swfupload
On 15 Jan 2009, at 19:55, sarah wrote:> What is happening for us is that I am able to get the content-type as > "image/jpeg" using mimetype_fu, but that is as far as things go. If I > then try to save that data in the controller (using attachment_fu), > like so: > > image_params = {:uploaded_data => params[''image_uploaded_data'']} > image = @visual_note.build_image(image_params.merge(:created_by => > current_user)) > if image.valid? > #do stuff > else > #errors > end > > > Errors are thrown because file_data -- the string passed in through my > params[:image_uploaded_data] from Flash does not respond to > content_type or original_filename > > *** > > Am I missing something from the point where the I am receiving the > data in the controller and getting it to attachment_fu? It doesn''t > know it is application/octet-stream because it doesn''t respond to > content-type at the controller level.How about: image_params = {:temp_data => params[''image_uploaded_data''], :filename => "whateveruwant", :content_type => "image/jpeg" } image = @visual_note.build_image(image_params.merge(:created_by => current_user)) if image.valid? #do stuff else #errors end Means the data that comes from Flash will be processed and you manually set the other fields. Best regards Peter De Berdt --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
sarah
2009-Jan-16 04:47 UTC
Re: application/octet-stream from flash: binary data, not swfupload
Interesting. This is definitely a step in a productive direction and I am very thankful for the suggestions that you have given. It''s not *quite* doing the trick, but it''s the closest I''ve been so far. Here''s the scoop: First, to do this, I had to make :content_type and :filename :attr_accessible and make a setter for temp_data in my asset class, since it''s not a setter attribute. This method calls set_temp_data in attachment_fu, like so: def temp_data set_temp_data(data) end I then followed your suggestion in the controller, like so, but getting the mime_type from mimetype_fu, in case it''s not always "image/ jpeg" image_params = {:temp_data => params [''image_uploaded_data''], :filename=> params [''image_uploaded_data''], :content_type => File.mime_type?(params [''image_uploaded_data''])} Note that each of values is the same field: params [''image_uploaded_data''] is the string of the filename that comes in. At this point, I ran the code and for the first time the process worked: the image validated, and it was stored on s3. However, the image itself was not the image exported from Flash: it was a jpeg *of* the string of filename. You can see it here: http://s3.amazonaws.com/canvasband_development/assets/255/v1/1152215550.jpg Weird. So I looked more closely at attachment_fu, and saw that in the uploaded_data= method, the seemingly relevant lines here pass the data from the file to set_temp_data, like so: (line 334) if file_data.is_a?(StringIO) file_data.rewind set_temp_data file_data.read else self.temp_paths.unshift file_data end So I switched my temp data setter to mimic that: def temp_data=(data) data.rewind set_temp_data(data.read) end and tried again, at which point I received the error: NoMethodError (undefined method `rewind'' for "1152233660.jpg":String) So I then tried to convert the string to a stringIO object, def temp_data=(data) datastr = StringIO.new(data) datastr.rewind set_temp_data(datastr.read) end Which then worked again -- ie, saved and uploaded the image -- except the "image" it saved was still a jpeg of the filename, again visible on s3 http://s3.amazonaws.com/canvasband_development/assets/263/v1/1152241736_thumb.jpg, but not what Flash sent in. Which seems to bring me back to the original problem, namely: despite the fact that the binary data is coming into the application, by the time I''m in the controller I can''t figure out how to access that data, and am only managing to get this pseudo-image. Is there anything else you can think of here? Thanks again for your input thus far, Sarah On Jan 15, 5:06 pm, Peter De Berdt <peter.de.be...-LPO8gxj9N8aZIoH1IeqzKA@public.gmane.org> wrote:> On 15 Jan 2009, at 19:55, sarah wrote: > > > > > What is happening for us is that I am able to get the content-type as > > "image/jpeg" using mimetype_fu, but that is as far as things go. If I > > then try to save that data in the controller (using attachment_fu), > > like so: > > > image_params = {:uploaded_data => params[''image_uploaded_data'']} > > image = @visual_note.build_image(image_params.merge(:created_by => > > current_user)) > > if image.valid? > > #do stuff > > else > > #errors > > end > > > Errors are thrown because file_data -- the string passed in through my > > params[:image_uploaded_data] from Flash does not respond to > > content_type or original_filename > > > *** > > > Am I missing something from the point where the I am receiving the > > data in the controller and getting it to attachment_fu? It doesn''t > > know it is application/octet-stream because it doesn''t respond to > > content-type at the controller level. > > How about: > > image_params = {:temp_data => params[''image_uploaded_data''], > :filename => "whateveruwant", > :content_type => "image/jpeg" > } > image = @visual_note.build_image(image_params.merge(:created_by => > current_user)) > if image.valid? > #do stuff > else > #errors > end > > Means the data that comes from Flash will be processed and you > manually set the other fields. > > Best regards > > Peter De Berdt--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---