mirror of
https://github.com/denoland/deno.git
synced 2024-10-29 08:58:01 -04:00
check runtime FormData
and Headers
params (#1415)
This commit is contained in:
parent
9bfe9a005b
commit
5e518b7417
5 changed files with 197 additions and 6 deletions
|
@ -3,6 +3,7 @@ import * as domTypes from "./dom_types";
|
|||
import * as blob from "./blob";
|
||||
import * as file from "./file";
|
||||
import { DomIterableMixin } from "./mixins/dom_iterable";
|
||||
import { requiredArguments } from "./util";
|
||||
|
||||
const dataSymbol = Symbol("data");
|
||||
|
||||
|
@ -18,6 +19,8 @@ class FormDataBase {
|
|||
append(name: string, value: string): void;
|
||||
append(name: string, value: blob.DenoBlob, filename?: string): void;
|
||||
append(name: string, value: string | blob.DenoBlob, filename?: string): void {
|
||||
requiredArguments("FormData.append", arguments.length, 2);
|
||||
name = String(name);
|
||||
if (value instanceof blob.DenoBlob) {
|
||||
const dfile = new file.DenoFile([value], filename || name);
|
||||
this[dataSymbol].push([name, dfile]);
|
||||
|
@ -31,6 +34,8 @@ class FormDataBase {
|
|||
* formData.delete('name');
|
||||
*/
|
||||
delete(name: string): void {
|
||||
requiredArguments("FormData.delete", arguments.length, 1);
|
||||
name = String(name);
|
||||
let i = 0;
|
||||
while (i < this[dataSymbol].length) {
|
||||
if (this[dataSymbol][i][0] === name) {
|
||||
|
@ -47,6 +52,8 @@ class FormDataBase {
|
|||
* formData.getAll('name');
|
||||
*/
|
||||
getAll(name: string): domTypes.FormDataEntryValue[] {
|
||||
requiredArguments("FormData.getAll", arguments.length, 1);
|
||||
name = String(name);
|
||||
const values = [];
|
||||
for (const entry of this[dataSymbol]) {
|
||||
if (entry[0] === name) {
|
||||
|
@ -63,6 +70,8 @@ class FormDataBase {
|
|||
* formData.get('name');
|
||||
*/
|
||||
get(name: string): domTypes.FormDataEntryValue | null {
|
||||
requiredArguments("FormData.get", arguments.length, 1);
|
||||
name = String(name);
|
||||
for (const entry of this[dataSymbol]) {
|
||||
if (entry[0] === name) {
|
||||
return entry[1];
|
||||
|
@ -78,23 +87,53 @@ class FormDataBase {
|
|||
* formData.has('name');
|
||||
*/
|
||||
has(name: string): boolean {
|
||||
requiredArguments("FormData.has", arguments.length, 1);
|
||||
name = String(name);
|
||||
return this[dataSymbol].some(entry => entry[0] === name);
|
||||
}
|
||||
|
||||
/** Sets a new value for an existing key inside a `FormData` object, or
|
||||
* adds the key/value if it does not already exist.
|
||||
* ref: https://xhr.spec.whatwg.org/#dom-formdata-set
|
||||
*
|
||||
* formData.set('name', 'value');
|
||||
*/
|
||||
set(name: string, value: string): void;
|
||||
set(name: string, value: blob.DenoBlob, filename?: string): void;
|
||||
set(name: string, value: string | blob.DenoBlob, filename?: string): void {
|
||||
this.delete(name);
|
||||
if (value instanceof blob.DenoBlob) {
|
||||
const dfile = new file.DenoFile([value], filename || name);
|
||||
this[dataSymbol].push([name, dfile]);
|
||||
} else {
|
||||
this[dataSymbol].push([name, String(value)]);
|
||||
requiredArguments("FormData.set", arguments.length, 2);
|
||||
name = String(name);
|
||||
|
||||
// If there are any entries in the context object’s entry list whose name
|
||||
// is name, replace the first such entry with entry and remove the others
|
||||
let found = false;
|
||||
let i = 0;
|
||||
while (i < this[dataSymbol].length) {
|
||||
if (this[dataSymbol][i][0] === name) {
|
||||
if (!found) {
|
||||
if (value instanceof blob.DenoBlob) {
|
||||
const dfile = new file.DenoFile([value], filename || name);
|
||||
this[dataSymbol][i][1] = dfile;
|
||||
} else {
|
||||
this[dataSymbol][i][1] = String(value);
|
||||
}
|
||||
found = true;
|
||||
} else {
|
||||
this[dataSymbol].splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Otherwise, append entry to the context object’s entry list.
|
||||
if (!found) {
|
||||
if (value instanceof blob.DenoBlob) {
|
||||
const dfile = new file.DenoFile([value], filename || name);
|
||||
this[dataSymbol].push([name, dfile]);
|
||||
} else {
|
||||
this[dataSymbol].push([name, String(value)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,3 +96,73 @@ test(function formDataParamsForEachSuccess() {
|
|||
});
|
||||
assertEqual(callNum, init.length);
|
||||
});
|
||||
|
||||
test(function formDataParamsArgumentsCheck() {
|
||||
const methodRequireOneParam = ["delete", "getAll", "get", "has", "forEach"];
|
||||
|
||||
const methodRequireTwoParams = ["append", "set"];
|
||||
|
||||
methodRequireOneParam.forEach(method => {
|
||||
const formData = new FormData();
|
||||
let hasThrown = 0;
|
||||
let errMsg = "";
|
||||
try {
|
||||
formData[method]();
|
||||
hasThrown = 1;
|
||||
} catch (err) {
|
||||
errMsg = err.message;
|
||||
if (err instanceof TypeError) {
|
||||
hasThrown = 2;
|
||||
} else {
|
||||
hasThrown = 3;
|
||||
}
|
||||
}
|
||||
assertEqual(hasThrown, 2);
|
||||
assertEqual(
|
||||
errMsg,
|
||||
`FormData.${method} requires at least 1 argument, but only 0 present`
|
||||
);
|
||||
});
|
||||
|
||||
methodRequireTwoParams.forEach(method => {
|
||||
const formData = new FormData();
|
||||
let hasThrown = 0;
|
||||
let errMsg = "";
|
||||
|
||||
try {
|
||||
formData[method]();
|
||||
hasThrown = 1;
|
||||
} catch (err) {
|
||||
errMsg = err.message;
|
||||
if (err instanceof TypeError) {
|
||||
hasThrown = 2;
|
||||
} else {
|
||||
hasThrown = 3;
|
||||
}
|
||||
}
|
||||
assertEqual(hasThrown, 2);
|
||||
assertEqual(
|
||||
errMsg,
|
||||
`FormData.${method} requires at least 2 arguments, but only 0 present`
|
||||
);
|
||||
|
||||
hasThrown = 0;
|
||||
errMsg = "";
|
||||
try {
|
||||
formData[method]("foo");
|
||||
hasThrown = 1;
|
||||
} catch (err) {
|
||||
errMsg = err.message;
|
||||
if (err instanceof TypeError) {
|
||||
hasThrown = 2;
|
||||
} else {
|
||||
hasThrown = 3;
|
||||
}
|
||||
}
|
||||
assertEqual(hasThrown, 2);
|
||||
assertEqual(
|
||||
errMsg,
|
||||
`FormData.${method} requires at least 2 arguments, but only 1 present`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types";
|
||||
import { DomIterableMixin } from "./mixins/dom_iterable";
|
||||
import { requiredArguments } from "./util";
|
||||
|
||||
// From node-fetch
|
||||
// Copyright (c) 2016 David Frank. MIT License.
|
||||
|
@ -75,6 +76,7 @@ class HeadersBase {
|
|||
|
||||
// ref: https://fetch.spec.whatwg.org/#concept-headers-append
|
||||
append(name: string, value: string): void {
|
||||
requiredArguments("Headers.append", arguments.length, 2);
|
||||
const [newname, newvalue] = this._normalizeParams(name, value);
|
||||
this._validateName(newname);
|
||||
this._validateValue(newvalue);
|
||||
|
@ -84,12 +86,14 @@ class HeadersBase {
|
|||
}
|
||||
|
||||
delete(name: string): void {
|
||||
requiredArguments("Headers.delete", arguments.length, 1);
|
||||
const [newname] = this._normalizeParams(name);
|
||||
this._validateName(newname);
|
||||
this[headerMap].delete(newname);
|
||||
}
|
||||
|
||||
get(name: string): string | null {
|
||||
requiredArguments("Headers.get", arguments.length, 1);
|
||||
const [newname] = this._normalizeParams(name);
|
||||
this._validateName(newname);
|
||||
const value = this[headerMap].get(newname);
|
||||
|
@ -97,12 +101,14 @@ class HeadersBase {
|
|||
}
|
||||
|
||||
has(name: string): boolean {
|
||||
requiredArguments("Headers.has", arguments.length, 1);
|
||||
const [newname] = this._normalizeParams(name);
|
||||
this._validateName(newname);
|
||||
return this[headerMap].has(newname);
|
||||
}
|
||||
|
||||
set(name: string, value: string): void {
|
||||
requiredArguments("Headers.set", arguments.length, 2);
|
||||
const [newname, newvalue] = this._normalizeParams(name, value);
|
||||
this._validateName(newname);
|
||||
this._validateValue(newvalue);
|
||||
|
|
|
@ -228,3 +228,73 @@ test(function headerIllegalReject() {
|
|||
// 'o k' is valid value but invalid name
|
||||
new Headers({ "He-y": "o k" });
|
||||
});
|
||||
|
||||
test(function headerParamsArgumentsCheck() {
|
||||
const methodRequireOneParam = ["delete", "get", "has", "forEach"];
|
||||
|
||||
const methodRequireTwoParams = ["append", "set"];
|
||||
|
||||
methodRequireOneParam.forEach(method => {
|
||||
const headers = new Headers();
|
||||
let hasThrown = 0;
|
||||
let errMsg = "";
|
||||
try {
|
||||
headers[method]();
|
||||
hasThrown = 1;
|
||||
} catch (err) {
|
||||
errMsg = err.message;
|
||||
if (err instanceof TypeError) {
|
||||
hasThrown = 2;
|
||||
} else {
|
||||
hasThrown = 3;
|
||||
}
|
||||
}
|
||||
assertEqual(hasThrown, 2);
|
||||
assertEqual(
|
||||
errMsg,
|
||||
`Headers.${method} requires at least 1 argument, but only 0 present`
|
||||
);
|
||||
});
|
||||
|
||||
methodRequireTwoParams.forEach(method => {
|
||||
const headers = new Headers();
|
||||
let hasThrown = 0;
|
||||
let errMsg = "";
|
||||
|
||||
try {
|
||||
headers[method]();
|
||||
hasThrown = 1;
|
||||
} catch (err) {
|
||||
errMsg = err.message;
|
||||
if (err instanceof TypeError) {
|
||||
hasThrown = 2;
|
||||
} else {
|
||||
hasThrown = 3;
|
||||
}
|
||||
}
|
||||
assertEqual(hasThrown, 2);
|
||||
assertEqual(
|
||||
errMsg,
|
||||
`Headers.${method} requires at least 2 arguments, but only 0 present`
|
||||
);
|
||||
|
||||
hasThrown = 0;
|
||||
errMsg = "";
|
||||
try {
|
||||
headers[method]("foo");
|
||||
hasThrown = 1;
|
||||
} catch (err) {
|
||||
errMsg = err.message;
|
||||
if (err instanceof TypeError) {
|
||||
hasThrown = 2;
|
||||
} else {
|
||||
hasThrown = 3;
|
||||
}
|
||||
}
|
||||
assertEqual(hasThrown, 2);
|
||||
assertEqual(
|
||||
errMsg,
|
||||
`Headers.${method} requires at least 2 arguments, but only 1 present`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { DomIterable } from "../dom_types";
|
||||
import { globalEval } from "../global_eval";
|
||||
import { requiredArguments } from "../util";
|
||||
|
||||
// if we import it directly from "globals" it will break the unit tests so we
|
||||
// have to grab a reference to the global scope a different way
|
||||
|
@ -52,6 +53,11 @@ export function DomIterableMixin<K, V, TBase extends Constructor>(
|
|||
// tslint:disable-next-line:no-any
|
||||
thisArg?: any
|
||||
): void {
|
||||
requiredArguments(
|
||||
`${this.constructor.name}.forEach`,
|
||||
arguments.length,
|
||||
1
|
||||
);
|
||||
callbackfn = callbackfn.bind(thisArg == null ? window : Object(thisArg));
|
||||
for (const [key, value] of (this as any)[dataSymbol]) {
|
||||
callbackfn(value, key, this);
|
||||
|
|
Loading…
Reference in a new issue