Bug 1109751 - Request and Response constructors should set mime type. r=baku

This commit is contained in:
Nikhil Marathe 2015-02-03 12:59:32 -08:00
parent a046c429cf
commit c6995aeda0
5 changed files with 74 additions and 31 deletions

View File

@ -1525,7 +1525,17 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
data.Adopt(reinterpret_cast<char*>(aResult), aResultLength);
autoFree.Reset();
if (StringBeginsWith(mMimeType, NS_LITERAL_CSTRING("multipart/form-data"))) {
NS_NAMED_LITERAL_CSTRING(formDataMimeType, NS_LITERAL_CSTRING("multipart/form-data"));
// Allow semicolon separated boundary/encoding suffix like multipart/form-data; boundary=
// but disallow multipart/form-datafoobar.
bool isValidFormDataMimeType = StringBeginsWith(mMimeType, formDataMimeType);
if (isValidFormDataMimeType && mMimeType.Length() > formDataMimeType.Length()) {
isValidFormDataMimeType = mMimeType[formDataMimeType.Length()] == ';';
}
if (isValidFormDataMimeType) {
FormDataParser parser(mMimeType, data, DerivedClass()->GetParentObject());
if (!parser.Parse()) {
ErrorResult result;
@ -1537,18 +1547,26 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
nsRefPtr<nsFormData> fd = parser.FormData();
MOZ_ASSERT(fd);
localPromise->MaybeResolve(fd);
} else if (StringBeginsWith(mMimeType,
NS_LITERAL_CSTRING("application/x-www-form-urlencoded"))) {
nsRefPtr<URLSearchParams> params = new URLSearchParams();
params->ParseInput(data, /* aObserver */ nullptr);
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
params->ForEach(FillFormData, static_cast<void*>(fd));
localPromise->MaybeResolve(fd);
} else {
ErrorResult result;
result.ThrowTypeError(MSG_BAD_FORMDATA);
localPromise->MaybeReject(result);
NS_NAMED_LITERAL_CSTRING(urlDataMimeType, NS_LITERAL_CSTRING("application/x-www-form-urlencoded"));
bool isValidUrlEncodedMimeType = StringBeginsWith(mMimeType, urlDataMimeType);
if (isValidUrlEncodedMimeType && mMimeType.Length() > urlDataMimeType.Length()) {
isValidUrlEncodedMimeType = mMimeType[urlDataMimeType.Length()] == ';';
}
if (isValidUrlEncodedMimeType) {
nsRefPtr<URLSearchParams> params = new URLSearchParams();
params->ParseInput(data, /* aObserver */ nullptr);
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
params->ForEach(FillFormData, static_cast<void*>(fd));
localPromise->MaybeResolve(fd);
} else {
ErrorResult result;
result.ThrowTypeError(MSG_BAD_FORMDATA);
localPromise->MaybeReject(result);
}
}
return;
}
@ -1626,15 +1644,15 @@ FetchBody<Response>::ConsumeBody(ConsumeType aType, ErrorResult& aRv);
template <class Derived>
void
FetchBody<Derived>::SetMimeType(ErrorResult& aRv)
FetchBody<Derived>::SetMimeType()
{
// Extract mime type.
ErrorResult result;
nsTArray<nsCString> contentTypeValues;
MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"),
contentTypeValues, result);
MOZ_ALWAYS_TRUE(!result.Failed());
// HTTP ABNF states Content-Type may have only one value.
// This is from the "parse a header value" of the fetch spec.
@ -1646,10 +1664,10 @@ FetchBody<Derived>::SetMimeType(ErrorResult& aRv)
template
void
FetchBody<Request>::SetMimeType(ErrorResult& aRv);
FetchBody<Request>::SetMimeType();
template
void
FetchBody<Response>::SetMimeType(ErrorResult& aRv);
FetchBody<Response>::SetMimeType();
} // namespace dom
} // namespace mozilla

View File

@ -160,7 +160,7 @@ protected:
virtual ~FetchBody();
void
SetMimeType(ErrorResult& aRv);
SetMimeType();
private:
enum ConsumeType
{

View File

@ -34,6 +34,7 @@ Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest)
, mOwner(aOwner)
, mRequest(aRequest)
{
SetMimeType();
}
Request::~Request()
@ -264,7 +265,7 @@ Request::Constructor(const GlobalObject& aGlobal,
}
nsRefPtr<Request> domRequest = new Request(global, request);
domRequest->SetMimeType(aRv);
domRequest->SetMimeType();
return domRequest.forget();
}

View File

@ -38,6 +38,7 @@ Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse
, mOwner(aGlobal)
, mInternalResponse(aInternalResponse)
{
SetMimeType();
}
Response::~Response()
@ -188,7 +189,7 @@ Response::Constructor(const GlobalObject& aGlobal,
}
}
r->SetMimeType(aRv);
r->SetMimeType();
return r.forget();
}

View File

@ -337,8 +337,8 @@ function testFormDataBodyExtraction() {
var req = new Request("", { method: 'POST', body: params });
var p1 = req.formData().then(function(fd) {
ok(fd.has("item"));
ok(fd.has("feature"));
ok(fd.has("item"), "Has entry 'item'.");
ok(fd.has("feature"), "Has entry 'feature'.");
var entries = fd.getAll("quantity");
is(entries.length, 2, "Entries with same name are correctly handled.");
is(entries[0], "700", "Entries with same name are correctly handled.");
@ -351,9 +351,9 @@ function testFormDataBodyExtraction() {
f1.append("blob", new Blob([text]));
var r2 = new Request("", { method: 'post', body: f1 });
var p2 = r2.formData().then(function(fd) {
ok(fd.has("key"));
ok(fd.has("foo"));
ok(fd.has("blob"));
ok(fd.has("key"), "Has entry 'key'.");
ok(fd.has("foo"), "Has entry 'foo'.");
ok(fd.has("blob"), "Has entry 'blob'.");
var entries = fd.getAll("blob");
is(entries.length, 1, "getAll returns all items.");
is(entries[0].name, "blob", "Filename should be blob.");
@ -363,13 +363,13 @@ function testFormDataBodyExtraction() {
f1.set("key", new File([ws], 'file name has spaces.txt', { type: 'new/lines' }));
var r3 = new Request("", { method: 'post', body: f1 });
var p3 = r3.formData().then(function(fd) {
ok(fd.has("foo"));
ok(fd.has("blob"));
ok(fd.has("foo"), "Has entry 'foo'.");
ok(fd.has("blob"), "Has entry 'blob'.");
var entries = fd.getAll("blob");
is(entries.length, 1, "getAll returns all items.");
is(entries[0].name, "blob", "Filename should be blob.");
ok(fd.has("key"));
ok(fd.has("key"), "Has entry 'key'.");
var f = fd.get("key");
ok(f instanceof File, "entry should be a File.");
is(f.name, "file name has spaces.txt", "File name should match.");
@ -380,7 +380,30 @@ function testFormDataBodyExtraction() {
});
});
return Promise.all([p1, p2, p3]);
// Override header and ensure parse fails.
var boundary = "1234567891011121314151617";
var body = boundary +
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
boundary + '-';
var r4 = new Request("", { method: 'post', body: body, headers: {
"Content-Type": "multipart/form-datafoobar; boundary="+boundary,
}});
var p4 = r4.formData().then(function() {
ok(false, "Invalid mimetype should fail.");
}, function() {
ok(true, "Invalid mimetype should fail.");
});
var r5 = new Request("", { method: 'POST', body: params, headers: {
"Content-Type": "application/x-www-form-urlencodedfoobar",
}});
var p5 = r5.formData().then(function() {
ok(false, "Invalid mimetype should fail.");
}, function() {
ok(true, "Invalid mimetype should fail.");
});
return Promise.all([p1, p2, p3, p4]);
}
// mode cannot be set to "CORS-with-forced-preflight" from javascript.