Skip to content

Commit

Permalink
Change body() to read, cache, and return ByteString. Implement hasFor…
Browse files Browse the repository at this point in the history
…mData() and friends.
  • Loading branch information
Tom Robinson committed Oct 15, 2009
1 parent 3ee7b56 commit 1165088
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 8 deletions.
79 changes: 71 additions & 8 deletions lib/jack/request.js
Expand Up @@ -9,7 +9,13 @@ var Request = exports.Request = function(env) {
this.env["jack.request"] = this;
}

Request.prototype.body = function() { return this.env["jsgi.input"]; };
Request.prototype.body = function() {
if (!this.env["jack.request.body"])
this.env["jack.request.body"] = this.env["jsgi.input"].read();

return this.env["jack.request.body"];
};

Request.prototype.scheme = function() { return this.env["jsgi.url_scheme"]; };
Request.prototype.scriptName = function() { return this.env["SCRIPT_NAME"]; };
Request.prototype.pathInfo = function() { return this.env["PATH_INFO"]; };
Expand All @@ -19,7 +25,7 @@ Request.prototype.queryString = function() { return this.env["QUERY_STRING"]
Request.prototype.referer = function() { return this.env["HTTP_REFERER"]; };
Request.prototype.referrer = Request.prototype.referer;
Request.prototype.contentLength = function() { return parseInt(this.env["CONTENT_LENGTH"], 10); };
Request.prototype.contentType = function() { return this.env["CONTENT_TYPE"]; };
Request.prototype.contentType = function() { return this.env["CONTENT_TYPE"] || null; };

Request.prototype.host = function() {
// Remove port number.
Expand All @@ -32,6 +38,62 @@ Request.prototype.isPut = function() { return this.requestMethod() ===
Request.prototype.isDelete = function() { return this.requestMethod() === "DELETE"; };
Request.prototype.isHead = function() { return this.requestMethod() === "HEAD"; };

// The set of form-data media-types. Requests that do not indicate
// one of the media types presents in this list will not be eligible
// for form-data / param parsing.
var FORM_DATA_MEDIA_TYPES = [
null,
'application/x-www-form-urlencoded',
'multipart/form-data'
]

// Determine whether the request body contains form-data by checking
// the request media_type against registered form-data media-types:
// "application/x-www-form-urlencoded" and "multipart/form-data". The
// list of form-data media types can be modified through the
// +FORM_DATA_MEDIA_TYPES+ array.
Request.prototype.hasFormData = function() {
var mediaType = this.mediaType();
return FORM_DATA_MEDIA_TYPES.reduce(function(x, type) { return x || type == mediaType; }, false);
}

// The media type (type/subtype) portion of the CONTENT_TYPE header
// without any media type parameters. e.g., when CONTENT_TYPE is
// "text/plain;charset=utf-8", the media-type is "text/plain".
//
// For more information on the use of media types in HTTP, see:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
Request.prototype.mediaType = function() {
var contentType = this.contentType();
return (contentType && contentType.split(/\s*[;,]\s*/, 2)[0].toLowerCase()) || null;
}

// The media type parameters provided in CONTENT_TYPE as a Hash, or
// an empty Hash if no CONTENT_TYPE or media-type parameters were
// provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
// this method responds with the following Hash:
// { 'charset' => 'utf-8' }
Request.prototype.mediaTypeParams = function() {
var contentType = this.contentType();
if (!contentType) return {};

return contentType.split(/\s*[;,]\s*/).slice(1).map(
function (s) { return s.split('=', 2); }).reduce(
function (hash, pair) {
hash[pair[0].toLowerCase()] = pair[1];
return hash;
}, {});
}

// The character set of the request body if a "charset" media type
// parameter was given, or nil if no "charset" was specified. Note
// that, per RFC2616, text/* media types that specify no explicit
// charset are to be considered ISO-8859-1.
Request.prototype.contentCharset = function() {
return this.mediaTypeParams()['charset'] || null;
}

// Returns the data recieved in the query string.
Request.prototype.GET = function() {
// cache the parsed query:
if (this.env["jack.request.query_string"] !== this.queryString()) {
Expand All @@ -45,16 +107,19 @@ Request.prototype.GET = function() {
return this.env["jack.request.query_hash"];
}

// Returns the data recieved in the request body.
//
// This method support both application/x-www-form-urlencoded and
// multipart/form-data.
Request.prototype.POST = function() {
var hash = {};
if (this.env["jack.request.form_input"] === this.env["jsgi.input"])
hash = this.env["jack.request.form_hash"];
// TODO: implement hasFormData
else if (true || this.hasFormData()) {
else if (this.hasFormData()) {
this.env["jack.request.form_input"] = this.env["jsgi.input"];
this.env["jack.request.form_hash"] = utils.parseMultipart(this.env);
if (!this.env["jack.request.form_hash"]) {
this.env["jack.request.form_vars"] = this.env["jsgi.input"].read().decodeToString("utf-8");
this.env["jack.request.form_vars"] = this.body().decodeToString("utf-8");
this.env["jack.request.form_hash"] = utils.parseQuery(this.env["jack.request.form_vars"]);
//this.env["jsgi.input"].rewind();
}
Expand Down Expand Up @@ -120,9 +185,7 @@ Request.prototype.uri = function() {

var XHR_RE = new RegExp("XMLHttpRequest", "i");

/**
* http://www.dev411.com/blog/2006/06/30/should-there-be-a-xmlhttprequest-user-agent
*/
// http://www.dev411.com/blog/2006/06/30/should-there-be-a-xmlhttprequest-user-agent
Request.prototype.isXHR = Request.prototype.isXMLHTTPRequest = function() {
return XHR_RE.test(this.env["HTTP_X_REQUESTED_WITH"]);
}
30 changes: 30 additions & 0 deletions tests/jack/request-tests.js
Expand Up @@ -16,3 +16,33 @@ exports.testParseCookiesRFC2109 = function() {

assert.isSame({"foo" : "bar"}, req.cookies());
}

exports.testMediaType = function() {
var req = new Request(MockRequest.envFor(null, "", { "CONTENT_TYPE" : "text/html" }));
assert.isEqual(req.mediaType(), "text/html");
assert.isEqual(req.contentType(), "text/html");

var req = new Request(MockRequest.envFor(null, "", { "CONTENT_TYPE" : "text/html; charset=utf-8" }));
assert.isEqual(req.mediaType(), "text/html");
assert.isEqual(req.contentType(), "text/html; charset=utf-8");
assert.isEqual(req.mediaTypeParams()["charset"], "utf-8");
assert.isEqual(req.contentCharset(), "utf-8");

var req = new Request(MockRequest.envFor(null, "", {}));
assert.isEqual(req.mediaType(), null);
assert.isEqual(req.contentType(), null);
}

exports.testHasFormData = function() {
var req = new Request(MockRequest.envFor(null, "", { "CONTENT_TYPE" : "application/x-www-form-urlencoded" }));
assert.isEqual(req.hasFormData(), true);

var req = new Request(MockRequest.envFor(null, "", { "CONTENT_TYPE" : "multipart/form-data" }));
assert.isEqual(req.hasFormData(), true);

var req = new Request(MockRequest.envFor(null, "", {}));
assert.isEqual(req.hasFormData(), true);

var req = new Request(MockRequest.envFor(null, "", { "CONTENT_TYPE" : "text/html" }));
assert.isEqual(req.hasFormData(), false);
}

0 comments on commit 1165088

Please sign in to comment.