3

My question is very similar to this one which describes how to serve a local file using Iron Router. I need to do the same, but instead of reading the file synchronously from disk, I need to get the file from S3 which is an asynchronous call.

The problem appears to be the fact that the action method has returned before the asynchronous s3.getObject completes giving me the following error.

Error: Can't render headers after they are sent to the client.

I'm assuming that Iron Router is generating the response for me when it realizes that I haven't handled the response in my action method, but I'm stumped about how to tell it to wait for my asynchronous call to finish.

Here is my code.

Router.map(function () {
    this.route('resumeDownload', {
        where: 'server',
        path: '/resume/:_id',
        action: function () {
            var response = this.response;

            var candidate = Candidates.findOne(this.params._id);
            if (!candidate || !candidate.resumeS3Key) {
                // this works fine because the method hasn't returned yet.
                response.writeHead(404);
                return response.end();
            }

            var s3 = new AWS.S3();
            s3.getObject({Bucket: 'myBucket', Key: candidate.resumeS3Key}, function (err, data) {
                if (err) {
                    // this will cause the error to be displayed
                    response.writeHead(500);
                    return response.end();
                }
                // this will also cause the error to be displayed
                response.writeHead(200, {'Content-Type': data.ContentType});
                response.end(data.Body);
            });
        }
    });
});
Community
  • 1
  • 1
Craig M
  • 5,598
  • 4
  • 32
  • 43

1 Answers1

4

I was able to solve this one myself. I needed to use a future in my action method.

Here is the working code.

Router.map(function () {
    this.route('resumeDownload', {
        where: 'server',
        path: '/resume/:_id',
        action: function () {
            var response = this.response,
                candidate = Candidates.findOne(this.params._id);

            if (!candidate || !candidate.resumeS3Key) {
                response.writeHead(404);
                return response.end();
            }

            var Future = Npm.require('fibers/future'),
                s3 = new AWS.S3(),
                futureGetObject = Future.wrap(s3.getObject.bind(s3)),
                data = futureGetObject({Bucket: 'myBucket', Key: candidate.resumeS3Key}).wait();

            response.writeHead(200, {'Content-Type': data.ContentType});
            response.end(data.Body);
        }
    });
});
Craig M
  • 5,598
  • 4
  • 32
  • 43