Skip to content

Commit

Permalink
support for nested params. Tests arent passing, some issue with bound…
Browse files Browse the repository at this point in the history
…aries
  • Loading branch information
mrjjwright committed Apr 11, 2010
1 parent 8723fed commit 164ba4b
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 87 deletions.
76 changes: 43 additions & 33 deletions lib/write.js
Expand Up @@ -58,12 +58,8 @@ function writer () { return new Writer() }
function Writer () {
this.firstPartReceived = false;
this.state = S.STARTED;
}

partToHeaderMap = { "name": "name"
, "type": "Content-Disposition"
, "filetype": "Content-Type"
, "filename": "filename"
this.depth = 0;
this.parts = [];
}

// Starts a part or nested part.
Expand All @@ -81,29 +77,46 @@ partToHeaderMap = { "name": "name"
// Optionally pass in a headers object of other headers
// e.g Content-Length, which will be appended to the headers.
Writer.prototype.partBegin = function (part, headers) {
writer = this;

var writer = this
, type = part["type"]
, partString = ""
, boundary = part["boundary"]
, name = part["name"]
, filename = part["filename"]
, currentPart = writer.parts[writer.parts.length-1];
;

//sys.debug("writer depth:" + writer.depth);
//sys.debug('writing part: ' + sys.inspect(part));

if (!writer.boundary) error(writer, "Missing property boundary on writer");

if (!type && !filename) {
error(writer, "Missing required type property on part.");
}

if (!type && filename) {
type = "inline";
} else {
type = "multipart/" + type;
}

if (!writer.depth && writer.state !== S.STARTED && writer.state !== S.PART_ENDED)
if (writer.state === S.WRITING)
return error(writer, "Illegal state. Cannot begin new part right now.");

if (writer.depth && !isMulti(part))
return error(writer, "Bad format. Cannot add part to non multipart parent.");
if (writer.state === S.PART_STARTED && currentPart.type !== "mixed")
return error(writer, "Bad format. Cannot add part to non multipart parent.");

//if (isMulti(partHeaders)) writer.depth++;

partString = "--" + writer.boundary + CRLF;
partString += "--" + writer.boundary + CRLF;

//write the Content-Disposition
contentDisposition = part["type"];
name = part["name"];
fileName = part["filename"];
if (!contentDisposition) error(writer, "Missing required type property on part.");
if (!name) error(writer, "Missing required name property on part.");
partString += "Content-Disposition: " + contentDisposition + "; name:\"" + name + "\"";
if (fileName) partString += "; filename=\"" + fileName + "\"";
partString += "Content-Type: " + type;
if (name) partString += "; name:'" + name + "'";
if (filename) partString += "; filename='" + filename + "'";
if (boundary) partString += "; boundary=" + boundary;
partString += CRLF;
// go down a nested part
if (type === "mixed") writer.depth++;

//write out any optional other headers
if (headers) {
Expand All @@ -113,6 +126,7 @@ Writer.prototype.partBegin = function (part, headers) {
}
emit(writer, "onData", partString + CRLF);
writer.state = S.PART_STARTED;
writer.parts.push(part);
}

// Writes a chunk to the multipart stream
Expand All @@ -133,17 +147,22 @@ Writer.prototype.write = function (chunk) {
// Writes the part end
// E.g. /r/n--boundary--
Writer.prototype.partEnd = function () {
var writer = this;
if (writer.state !== S.WRITING)
var writer = this
, currentPart = writer.parts[writer.parts.length-1]
;

if (currentPart && currentPart.type !== "mixed" && writer.state !== S.WRITING)
error(writer, "Illegal state. Must write at least one chunk to this part before calling partEnd");

emit(writer, "onData", CRLF + "--" + writer.boundary + "--" + CRLF);
writer.state = S.PART_ENDED;
writer.depth--;
currentPart = writer.parts.pop();
if (currentPart && currentPart.type === "mixed") writer.depth--;
}


Writer.prototype.close = function () {
var writer = this;
if (!writer.depth && writer.state === S.PART_ENDED) return emit(writer, "onEnd");
error(writer, "Illegal state. Multiparts not written completely before close.")
};
Expand Down Expand Up @@ -178,13 +197,4 @@ function writeHttpHeaders(writer) {
emit(writer, "onData", headerString + CRLF + CRLF);
}

function newPart (writer) {
var p =
{ headers:{}
, parent : writer.part
};
parent.parts = parent.parts || [];
parent.parts.push(p);
}


33 changes: 33 additions & 0 deletions test/fixture.js
Expand Up @@ -710,3 +710,36 @@ messages.push({
""
].join("\r\n")
});


exports.aSimpleMessage = {
headers: {
"Content-Type": "multipart/form-data; boundary=AaB03x",
},
boundary : "AaB03x",
parts: [ {
part: {
"type": "form-data", "name": "test"
}
, body: "hello"
, encoded: [
"--AaB03x"
, "content-disposition: form-data; name=\"test\""
, ""
, "hello"
].join(",")
}
, {
part: {
"type": "form-data", "name": "test1"
}
, body: "hello1"
, encoded: [
"--AaB03x"
, "content-disposition: form-data; name=\"test1\""
, ""
, "hello1"
].join(",")
}
]
};
123 changes: 69 additions & 54 deletions test/write.js
Expand Up @@ -2,57 +2,16 @@ var multipart = require("../lib/multipart")
, assert = require("assert")
, sys = require("sys")
, fixture = require("./fixture")
, testPart = function (expect, part) {
sys.debug("test part: "+sys.inspect(expect));
if (!expect) {
throw new Error("Got more parts than expected: "+
sys.inspect(part.headers));
}
for (var i in expect) {
assert.equal(expect[i], part[i]);
}
}
, messages = fixture.messages
, aSimpleMessage = fixture.aSimpleMessage
, aNestedMessage = messages[0]
, writer = multipart.writer()
, parser = multipart.parser()
, expect
, e
;


var messages = []
messages.push({
headers: {
"Content-Type": "multipart/form-data; boundary=AaB03x",
},
boundary : "AaB03x",
parts: [ {
part: {
"type": "form-data", "name": "test"
}
, body: "hello"
, encoded: [
"--AaB03x"
, "content-disposition: form-data; name=\"test\""
, ""
, "hello"
].join(",")
}
, {
part: {
"type": "form-data", "name": "test1"
}
, body: "hello1"
, encoded: [
"--AaB03x"
, "content-disposition: form-data; name=\"test1\""
, ""
, "hello1"
].join(",")
}
]
});

sys.debug("Create a multipart writer.");
sys.debug("");
assert.notEqual(writer, null, "should be able to obtain writer");
Expand Down Expand Up @@ -91,43 +50,99 @@ parser.onPartBegin = function (part) {
}

parser.onPartEnd = function (part) {
sys.debug("parser ended part succesfully: " + sys.inspect(part));
sys.debug("parser ended part succesfully");
}

parser.onEnd = function () {
sys.debug("parser ended");
}

parser.headers = messages[0].headers;
parser.headers = aSimpleMessage.headers;

sys.debug("Write a part without setting boundary...");
try {
writer.partBegin(messages[0].parts[0].part);
writer.partBegin(aSimpleMessage.parts[0].part);
assert.ok(errorHandlerCalled, "should emit onError if part written without boundary");
}catch (error) {
sys.puts(error.message);
assert.ok(errorHandlerCalled, "should emit onError if part written without boundary");
}

sys.debug("Set the boundary property and try again...");
writer.boundary = messages[0].boundary;
writer.partBegin(messages[0].parts[0].part);
writer.boundary = aSimpleMessage.boundary;
writer.partBegin(aSimpleMessage.parts[0].part);

sys.debug("Write the body...")
writer.write(messages[0].parts[0].body);
writer.write(aSimpleMessage.parts[0].body);

sys.debug("Start another part without finishing...");
try {
writer.partBegin(messages[0].parts[1].part);
writer.partBegin(aSimpleMessage.parts[1].part);
} catch (error1) {
assert.ok(errorHandlerCalled, "should emit onError if part written without finishing the part before");
}
sys.debug("Whoops, end the last part..")
writer.partEnd();

sys.debug("Start another simple part");
writer.partBegin(messages[0].parts[1].part);
sys.debug("Write body and end")
writer.write(messages[0].parts[1].body);
writer.partBegin(aSimpleMessage.parts[1].part);
sys.debug("Write body and finish.")
writer.write(aSimpleMessage.parts[1].body);
writer.partEnd();
writer.close();
parser.close();

sys.debug("Ok, looks good. Now write a more complicated nested multipart");

writer = multipart.writer();
parser = multipart.parser();

function testPart(expect, part) {
sys.debug("test part: "+sys.inspect(part));
if (!expect) {
throw new Error("Got more parts than expected: "+
sys.inspect(part.headers));
}
for (var i in expect) {
//assert.equal(expect[i], part[i]);
}
}

parser.onPartBegin = function (part) {
testPart(expect[e++], part);
}

writer.onData = function (chunk) {
parser.write(chunk);
}
//a nested test from the fixtures

var expect = aNestedMessage.expect
, e = 0;
parser.headers = aNestedMessage.headers;
writer.boundary = aNestedMessage.boundary;
writer.partBegin(aNestedMessage.expect[0]); //start inner 1 mixed
writer.partBegin(aNestedMessage.expect[1]); //start inner 2 mixed
writer.partBegin(aNestedMessage.expect[2]); //inner 2, part 1
writer.write("hello, world");
writer.partEnd();
writer.partBegin(aNestedMessage.expect[3]); //inner 2, part 2
writer.write("hello to the world");
writer.partEnd();
writer.close();
writer.partEnd(); //finish inner2
writer.partEnd(); //finish inner1
writer.partBegin(aNestedMessage.expect[4]); //start inner 3 mixed
writer.partBegin(aNestedMessage.expect[5]);
writer.write("hello, free the world"); // inner 3, part1
writer.partEnd();
writer.partBegin(aNestedMessage.expect[6]); // inner 3, part 2
writer.write("hello, for the world")
writer.partEnd();
writer.partEnd(); //end inner 3
writer.partBegin(aNestedMessage.expect[7]); // outer, part1
writer.write("hello, outer world");
writer.partEnd();
writer.partEnd(); //finish outer
writer.close();
parser.close();

0 comments on commit 164ba4b

Please sign in to comment.