Skip to content

Commit

Permalink
Multipart Upload Initiating
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Nov 28, 2011
1 parent 7da6ace commit 81c2b86
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions lib/knox/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,74 @@ Client.prototype.put = function(filename, headers){
return this.request('PUT', filename, headers);
};

/**
* Represens chunk builder that concatenates string chunks in the readable stream.
* @constructor
*/
function ChunkBuilder(){
this.data = '';
this.completed = false;
this.error = null;
this.append_chunk = function(chunk) { this.data += chunk }.bind(this);
this.complete = function() { this.completed = true }.bind(this);
this.catch_error = function(e) { this.error = e; this.completed = true }.bind(this);
}

/**
* Returns value of the XML element.
* @param {String} content XML document.
* @param {String} elementName The name of the XML element.
* @returns {String} Value of the specified XML element.
*/
function get_element_content(content, elementName){
var xmltag = '<' + elementName + '>';
var startpos = content.indexOf(xmltag) + xmltag.length;
xmltag = '</' + elementName + '>';
var endpos = content.indexOf(xmltag);
return content.substring(startpos, endpos);
}

/**
* Represents uploading initialization data.
* @param {String} rawxml XML markup accepted from Amazon S3 service. See http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?mpUploadInitiate.html
* @constructor
*/
function UploadInitResult(rawxml){
this.bucket = null;
this.key = null;
this.upload_id = null;
if(typeof rawxml == 'string'){
//The first, let's find Bucket name in the entire XML
this.bucket = get_element_content(rawxml, 'Bucket');
this.key = get_element_content(rawxml, 'Key');
this.upload_id = get_element_content(rawxml, 'UploadId');
}
}

/**
* Initiates multipart upload.
* @param {String} filename The name of the object on Amazon S3 service.
* @param {Object} headers Additional headers used in HTTP request to S3 service.
* @param {Function} fn A callback that accepts two parameters: err that holds exception info, and ir - multipart upload initiation result.
*/
Client.prototype.begin_upload = function(filename, headers, fn){
if(typeof headers == 'function') fn = headers;
filename += '?uploads'; //initiate uploading transaction, see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadInitiate.html
var request = this.request('POST', filename, headers);
//Upload initiating returns XML document in UTF-8 encoding that contains uploading ID.
request.on('response', function(response){
response.setEncoding('utf8'); //TODO: Encoding may be detected in more flexible way (or detected automatically).
if(response.statusCode != 200) fn({'statusCode': response.statusCode}, null);
else{
var builder = new ChunkBuilder(); //used for chunk concatenation.
response.on('data', function(chunk) { builder.append_chunk(chunk) }); //save chunks into the builder.
response.on('error', function(err) { builder.catch_error(err) }); //register error.
response.on('end', function(){ builder.complete(); fn(builder.error, new UploadInitResult(builder.data)); });
}
});
request.end();
};

/**
* PUT the file at `src` to `filename`, with callback `fn`
* receiving a possible exception, and the response object.
Expand Down

0 comments on commit 81c2b86

Please sign in to comment.