Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I upload a file to my ruby on rails app using curl CLI?

On the web side of things, I have two fields: name, and document. Document is a file field, and name is just what the user wants to call the file in the app.

Here is what I have tried:

curl -F "media[document][email protected]" -F "media[name]=api" "http://example.com/medias/create.xml?api_key=123"

but I get an InvalidAuthenticityToken Error. This error only occurs when I try to upload a file / make a media object. The other API / xml commands work (the ones not involving files)

what is the correct way to upload a file using cURL?

EDIT: adding -H "Content-Type: application/xml" to the above curl command make the server generate this error:

/!\ FAILSAFE /!\  Tue Jan 24 08:45:03 -0500 2012
  Status: 500 Internal Server Error
  #<REXML::ParseException: malformed XML: missing tag start
Line: 
Position: 
Last 80 unconsumed characters:
<:??OH?ɽ?H? ???g??yx~t????op?.$?????P&W ??"?

normally the XML is supplied using the -d argument. but I don't think files can be included in xml? maybe they can? idk.

like image 227
NullVoxPopuli Avatar asked Jan 20 '12 15:01

NullVoxPopuli


3 Answers

If you want to create file from xml, you should format your xml to use data, either Base64 and/or CDATA, depending of your needs. Once you have a corretly formatted xml file, you just have to send it with curl.

If you just want to upload file, you don't need to use an xml interface. You can just call :

curl -F "media[document]=@./a.png;type=image/png" -F "media[name]=api" "http://example.com/medias/

For your authentification problem, if you still have it on this url (I do not encounter it on a new rails 3.2.1 fresh app), you can access it with a regular browser, get the cookie information and send it with curl. It means that you will add to your command :

--cookie "csrf-param=authenticity_token" --cookie "csrf-value=XXXXXXX"

Or use a convenient script to send all your current Firefox cookies from an host into curl.

like image 93
Coren Avatar answered Nov 11 '22 04:11

Coren


Rails uses authenticity token to prevent CSRF. It inserts special token calculated based on current user's session into every form and checks it when request comes to the server.

When you perform POST request using curl you get that error as you're not passing valid authenticity token to the server. You can either disable that protection for you method like that (note, that disabling it will make this action vulnerable for CSRF):

protect_from_forgery :except => :some_action

or you can use some ninja magic to pass valid authenticity token to the server.

Another option is based on the fact that Rails checks authenticity token only for requests with certain content types. If it's an API and you're getting response in JSON you can try setting content type of the request to application/json like that:

curl -H "Content-Type: application/json" ...

See these links for more information: one, two, three.

like image 3
KL-7 Avatar answered Nov 11 '22 04:11

KL-7


You need to disable authenticity token for the action. Use this in your controller (I'm assuming the action is named create):

protect_from_forgery :except => [:create]

This only happens with POST, PUT or DELETE requests, that's probably why other request are successful.

If this is an API you will want to disable this entirely. You can remove protect_from_forgery in you ApplicationController.

The authenticity token is used to (somewhat) ensure that the user goes through the form when modifying resources. The application creates a random token associated with the user session and puts it in a hidden field of the form. When the form is submitted the token is compared with the one stored in the session to made the check. This won't have any sense in an API.

like image 2
aromero Avatar answered Nov 11 '22 05:11

aromero