sending a file using HTTP PUT

1,723 views
Skip to first unread message

josh

unread,
Jul 23, 2012, 10:53:54 PM7/23/12
to nod...@googlegroups.com
I try to make an HTTP PUT to an API.  this endpoint allow sending a file and it saves it somewhere for later retrieval.
Here is the way I do it (successfully) with curl:
curl -sSf -T file1 http://api.my-server/file1  (PUT)    and    curl -O -L http://api.my-server/file1  (GET)

Here is a verbose PUT: (the unique name of my file will be test-file-7)
curl -sSf -T file1 http://api.my-server.com:3000/test.bla/test-file-7 -v

> PUT /test.bla/test-file-7 HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: api.my-server.com:3000
> Accept: */*
> Content-Length: 12
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: nginx/0.6.34
< Date: Tue, 24 Jul 2012 02:10:18 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: close
< Vary: Accept-Encoding
< Status: 200 OK
<
* Closing connection #0



here is my node code that is trying to imitate the curl:

module.exports = saveFile;
 
var request = require('request');  // Mikeal's request package
var rand = Math.floor(Math.random()*100000000).toString();
 
// curl -sSf -T file1 <url>/file-name
function saveFile() {
  request({
    method: 'PUT',
    uri: 'http://api.my-server.com:3000/file-' + rand,
    multipart: [ {
        'content-type': 'application/json',
        body: JSON.stringify({
          foo: 'bar',
          _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}
        })
      },
      { body: 'I am an attachment' }
    ]
  }
  , function (error, response, body) {
      if(response.statusCode == 200){
        console.log('ok);
     } else {
       console.log('error: '+ response.statusCode)
       console.log(body)
     }
   });
};

the difference between this code and the curl version is i am not loading a file from the file system in the node version.
if this is the issue, can anyone guide me about doing it?  i probably need to change the content type and might not need the multipart? i am not sure.
 
here is the output i see in the terminal:
// boundary >> D0F5DF48-E3F9-4C8B-93F2-2A7EFA47F7C4
// ok
 
 
// when i retrieve the file from the server using curl -O -L http://api.my-server/file1
// i see:

cat file1 =>
--D0F5DF48-E3F9-4C8B-93F2-2A7EFA47F7C4
content-type: application/json
 
{"foo":"bar","_attachments":{"message.txt":{"follows":true,"length":18,"content_type":"text/plain"}}}
--D0F5DF48-E3F9-4C8B-93F2-2A7EFA47F7C4
 
I am an attachment
 
 

any idea why do i see so many lines instead of only the last one?
is it the multipart or maybe the content-type?

Also, I can talk to the guy that created the API i am using. i am just not sure what questions should I ask him.
Also, any insight about mutiparts, mime-types and encoding would be appreciated. this stuff is confusing!

Thanks!

Martin Cooper

unread,
Jul 23, 2012, 11:32:35 PM7/23/12
to nod...@googlegroups.com
On Mon, Jul 23, 2012 at 7:53 PM, josh <macmilla...@gmail.com> wrote:
> I try to make an HTTP PUT to an API. this endpoint allow sending a file and
> it saves it somewhere for later retrieval.

If you want to simply upload a file, you don't want to be making a
multipart request, which is what your Node code is doing. Instead, if
you have a small amount of data, just provide that as 'body' (not
inside 'multipart') in the request options. Better, though, is to
stream the body data, as in one of the earlier examples in the request
library readme.

--
Martin Cooper
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to
> nodejs+un...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en

josh

unread,
Jul 24, 2012, 12:46:59 PM7/24/12
to nod...@googlegroups.com
great. it works for simple string -
body: 'I am an attachment'

now I want to stream a file.
I am trying to pipe the readable stream of my file into the put request:
file = fs.createReadStream('test-file').pipe(request.put('http://api.my-server.com:3000/test.foo/test-7));

and it looks fine (nothing crashed) but i don't see the file when i curl my api.
i added the 'data' and 'end' events to the file, and i see the chunks, so it's sending it.

is there a way to view the server's response? right now i don't know if the put request was successful.


josh

unread,
Jul 24, 2012, 2:00:28 PM7/24/12
to nod...@googlegroups.com
btw i am able to do PUT using fs.readFile but i don't want to load each file into memory.
is my api suppose to support streaming or should this piping approach works with any server?

josh

unread,
Jul 25, 2012, 9:17:08 PM7/25/12
to nod...@googlegroups.com
problem solved:

    var file = fs.createReadStream(path)
      .pipe(request.put({url: url, headers:{'Content-Length': fileSize}}, function(err, res, body){
        if(err) {
          console.log('error', err);
        } else {
          console.log('status', res.statusCode);
          if(res.statusCode === 200) {
            console.log('success');
          }
        }
      }));


note: i had to pass the fileSize by using the async function fs.stat()
Reply all
Reply to author
Forward
0 new messages