Merge branch 'master' of https://codefirst.iut.uca.fr/git/noan.randon/Favor
commit
436dc2d1b0
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Favor.iml" filepath="$PROJECT_DIR$/.idea/Favor.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -1 +0,0 @@
|
|||||||
/node_modules
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,36 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
//e.preventDefaul(); pour ne pas recharcher la page
|
||||||
|
const Poste = (props) => {
|
||||||
|
return (
|
||||||
|
<div id="cadrePoste">
|
||||||
|
<div id="hautPoste">
|
||||||
|
<div id="cadreInfoPoste">
|
||||||
|
<img id="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
|
||||||
|
<h6 id="NomProfile">Lena 1er</h6>
|
||||||
|
</div>
|
||||||
|
<div>6 jours</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="contenuePoste">
|
||||||
|
/*utliser leakpreview*/
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="basPoste">
|
||||||
|
<div id="like">
|
||||||
|
<img src="coeurs.png"/>
|
||||||
|
<div>10k</div>
|
||||||
|
</div>
|
||||||
|
<div id="commentaire">
|
||||||
|
<img src="commentaire.png"/>
|
||||||
|
<div>10k</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//ce qui écrit dans le input est récuperé par le state
|
||||||
|
export default Poste;
|
@ -1,12 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
||||||
|
|
||||||
case `uname` in
|
|
||||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -x "$basedir/node" ]; then
|
|
||||||
exec "$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@"
|
|
||||||
else
|
|
||||||
exec node "$basedir/../mkdirp/bin/cmd.js" "$@"
|
|
||||||
fi
|
|
@ -1,17 +0,0 @@
|
|||||||
@ECHO off
|
|
||||||
GOTO start
|
|
||||||
:find_dp0
|
|
||||||
SET dp0=%~dp0
|
|
||||||
EXIT /b
|
|
||||||
:start
|
|
||||||
SETLOCAL
|
|
||||||
CALL :find_dp0
|
|
||||||
|
|
||||||
IF EXIST "%dp0%\node.exe" (
|
|
||||||
SET "_prog=%dp0%\node.exe"
|
|
||||||
) ELSE (
|
|
||||||
SET "_prog=node"
|
|
||||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
|
||||||
)
|
|
||||||
|
|
||||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mkdirp\bin\cmd.js" %*
|
|
@ -1,28 +0,0 @@
|
|||||||
#!/usr/bin/env pwsh
|
|
||||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
|
||||||
|
|
||||||
$exe=""
|
|
||||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
|
||||||
# Fix case when both the Windows and Linux builds of Node
|
|
||||||
# are installed in the same directory
|
|
||||||
$exe=".exe"
|
|
||||||
}
|
|
||||||
$ret=0
|
|
||||||
if (Test-Path "$basedir/node$exe") {
|
|
||||||
# Support pipeline input
|
|
||||||
if ($MyInvocation.ExpectingInput) {
|
|
||||||
$input | & "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
|
|
||||||
} else {
|
|
||||||
& "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
|
|
||||||
}
|
|
||||||
$ret=$LASTEXITCODE
|
|
||||||
} else {
|
|
||||||
# Support pipeline input
|
|
||||||
if ($MyInvocation.ExpectingInput) {
|
|
||||||
$input | & "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
|
|
||||||
} else {
|
|
||||||
& "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
|
|
||||||
}
|
|
||||||
$ret=$LASTEXITCODE
|
|
||||||
}
|
|
||||||
exit $ret
|
|
@ -1,198 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Favor",
|
|
||||||
"lockfileVersion": 2,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"node_modules/append-field": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
|
|
||||||
},
|
|
||||||
"node_modules/buffer-from": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
|
||||||
},
|
|
||||||
"node_modules/busboy": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
|
||||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
|
||||||
"dependencies": {
|
|
||||||
"streamsearch": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.16.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/concat-stream": {
|
|
||||||
"version": "1.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
|
||||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
|
||||||
"engines": [
|
|
||||||
"node >= 0.8"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"buffer-from": "^1.0.0",
|
|
||||||
"inherits": "^2.0.3",
|
|
||||||
"readable-stream": "^2.2.2",
|
|
||||||
"typedarray": "^0.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/core-util-is": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
|
||||||
},
|
|
||||||
"node_modules/inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
|
||||||
},
|
|
||||||
"node_modules/isarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
|
||||||
},
|
|
||||||
"node_modules/media-typer": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
|
||||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-db": {
|
|
||||||
"version": "1.52.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-types": {
|
|
||||||
"version": "2.1.35",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-db": "1.52.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minimist": {
|
|
||||||
"version": "1.2.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
|
|
||||||
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mkdirp": {
|
|
||||||
"version": "0.5.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
|
||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
|
||||||
"dependencies": {
|
|
||||||
"minimist": "^1.2.6"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"mkdirp": "bin/cmd.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/multer": {
|
|
||||||
"version": "1.4.5-lts.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
|
|
||||||
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"append-field": "^1.0.0",
|
|
||||||
"busboy": "^1.0.0",
|
|
||||||
"concat-stream": "^1.5.2",
|
|
||||||
"mkdirp": "^0.5.4",
|
|
||||||
"object-assign": "^4.1.1",
|
|
||||||
"type-is": "^1.6.4",
|
|
||||||
"xtend": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/object-assign": {
|
|
||||||
"version": "4.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/process-nextick-args": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
|
||||||
},
|
|
||||||
"node_modules/readable-stream": {
|
|
||||||
"version": "2.3.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
|
||||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
|
||||||
"dependencies": {
|
|
||||||
"core-util-is": "~1.0.0",
|
|
||||||
"inherits": "~2.0.3",
|
|
||||||
"isarray": "~1.0.0",
|
|
||||||
"process-nextick-args": "~2.0.0",
|
|
||||||
"safe-buffer": "~5.1.1",
|
|
||||||
"string_decoder": "~1.1.1",
|
|
||||||
"util-deprecate": "~1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/safe-buffer": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
|
||||||
},
|
|
||||||
"node_modules/streamsearch": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/string_decoder": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
|
||||||
"dependencies": {
|
|
||||||
"safe-buffer": "~5.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/type-is": {
|
|
||||||
"version": "1.6.18",
|
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
|
||||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
|
||||||
"dependencies": {
|
|
||||||
"media-typer": "0.3.0",
|
|
||||||
"mime-types": "~2.1.24"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/typedarray": {
|
|
||||||
"version": "0.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
|
||||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
|
||||||
},
|
|
||||||
"node_modules/util-deprecate": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
|
||||||
},
|
|
||||||
"node_modules/xtend": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
node_modules/
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Linus Unnebäck
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,44 +0,0 @@
|
|||||||
# `append-field`
|
|
||||||
|
|
||||||
A [W3C HTML JSON forms spec](http://www.w3.org/TR/html-json-forms/) compliant
|
|
||||||
field appender (for lack of a better name). Useful for people implementing
|
|
||||||
`application/x-www-form-urlencoded` and `multipart/form-data` parsers.
|
|
||||||
|
|
||||||
It works best on objects created with `Object.create(null)`. Otherwise it might
|
|
||||||
conflict with variables from the prototype (e.g. `hasOwnProperty`).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm install --save append-field
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var appendField = require('append-field')
|
|
||||||
var obj = Object.create(null)
|
|
||||||
|
|
||||||
appendField(obj, 'pets[0][species]', 'Dahut')
|
|
||||||
appendField(obj, 'pets[0][name]', 'Hypatia')
|
|
||||||
appendField(obj, 'pets[1][species]', 'Felis Stultus')
|
|
||||||
appendField(obj, 'pets[1][name]', 'Billie')
|
|
||||||
|
|
||||||
console.log(obj)
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
|
||||||
{ pets:
|
|
||||||
[ { species: 'Dahut', name: 'Hypatia' },
|
|
||||||
{ species: 'Felis Stultus', name: 'Billie' } ] }
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
### `appendField(store, key, value)`
|
|
||||||
|
|
||||||
Adds the field named `key` with the value `value` to the object `store`.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
@ -1,12 +0,0 @@
|
|||||||
var parsePath = require('./lib/parse-path')
|
|
||||||
var setValue = require('./lib/set-value')
|
|
||||||
|
|
||||||
function appendField (store, key, value) {
|
|
||||||
var steps = parsePath(key)
|
|
||||||
|
|
||||||
steps.reduce(function (context, step) {
|
|
||||||
return setValue(context, step, context[step.key], value)
|
|
||||||
}, store)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = appendField
|
|
@ -1,53 +0,0 @@
|
|||||||
var reFirstKey = /^[^\[]*/
|
|
||||||
var reDigitPath = /^\[(\d+)\]/
|
|
||||||
var reNormalPath = /^\[([^\]]+)\]/
|
|
||||||
|
|
||||||
function parsePath (key) {
|
|
||||||
function failure () {
|
|
||||||
return [{ type: 'object', key: key, last: true }]
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstKey = reFirstKey.exec(key)[0]
|
|
||||||
if (!firstKey) return failure()
|
|
||||||
|
|
||||||
var len = key.length
|
|
||||||
var pos = firstKey.length
|
|
||||||
var tail = { type: 'object', key: firstKey }
|
|
||||||
var steps = [tail]
|
|
||||||
|
|
||||||
while (pos < len) {
|
|
||||||
var m
|
|
||||||
|
|
||||||
if (key[pos] === '[' && key[pos + 1] === ']') {
|
|
||||||
pos += 2
|
|
||||||
tail.append = true
|
|
||||||
if (pos !== len) return failure()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
m = reDigitPath.exec(key.substring(pos))
|
|
||||||
if (m !== null) {
|
|
||||||
pos += m[0].length
|
|
||||||
tail.nextType = 'array'
|
|
||||||
tail = { type: 'array', key: parseInt(m[1], 10) }
|
|
||||||
steps.push(tail)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
m = reNormalPath.exec(key.substring(pos))
|
|
||||||
if (m !== null) {
|
|
||||||
pos += m[0].length
|
|
||||||
tail.nextType = 'object'
|
|
||||||
tail = { type: 'object', key: m[1] }
|
|
||||||
steps.push(tail)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return failure()
|
|
||||||
}
|
|
||||||
|
|
||||||
tail.last = true
|
|
||||||
return steps
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = parsePath
|
|
@ -1,64 +0,0 @@
|
|||||||
function valueType (value) {
|
|
||||||
if (value === undefined) return 'undefined'
|
|
||||||
if (Array.isArray(value)) return 'array'
|
|
||||||
if (typeof value === 'object') return 'object'
|
|
||||||
return 'scalar'
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLastValue (context, step, currentValue, entryValue) {
|
|
||||||
switch (valueType(currentValue)) {
|
|
||||||
case 'undefined':
|
|
||||||
if (step.append) {
|
|
||||||
context[step.key] = [entryValue]
|
|
||||||
} else {
|
|
||||||
context[step.key] = entryValue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'array':
|
|
||||||
context[step.key].push(entryValue)
|
|
||||||
break
|
|
||||||
case 'object':
|
|
||||||
return setLastValue(currentValue, { type: 'object', key: '', last: true }, currentValue[''], entryValue)
|
|
||||||
case 'scalar':
|
|
||||||
context[step.key] = [context[step.key], entryValue]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
|
|
||||||
function setValue (context, step, currentValue, entryValue) {
|
|
||||||
if (step.last) return setLastValue(context, step, currentValue, entryValue)
|
|
||||||
|
|
||||||
var obj
|
|
||||||
switch (valueType(currentValue)) {
|
|
||||||
case 'undefined':
|
|
||||||
if (step.nextType === 'array') {
|
|
||||||
context[step.key] = []
|
|
||||||
} else {
|
|
||||||
context[step.key] = Object.create(null)
|
|
||||||
}
|
|
||||||
return context[step.key]
|
|
||||||
case 'object':
|
|
||||||
return context[step.key]
|
|
||||||
case 'array':
|
|
||||||
if (step.nextType === 'array') {
|
|
||||||
return currentValue
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = Object.create(null)
|
|
||||||
context[step.key] = obj
|
|
||||||
currentValue.forEach(function (item, i) {
|
|
||||||
if (item !== undefined) obj['' + i] = item
|
|
||||||
})
|
|
||||||
|
|
||||||
return obj
|
|
||||||
case 'scalar':
|
|
||||||
obj = Object.create(null)
|
|
||||||
obj[''] = currentValue
|
|
||||||
context[step.key] = obj
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = setValue
|
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "append-field",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"author": "Linus Unnebäck <linus@folkdatorn.se>",
|
|
||||||
"main": "index.js",
|
|
||||||
"devDependencies": {
|
|
||||||
"mocha": "^2.2.4",
|
|
||||||
"standard": "^6.0.5",
|
|
||||||
"testdata-w3c-json-form": "^0.2.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "standard && mocha"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "http://github.com/LinusU/node-append-field.git"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
/* eslint-env mocha */
|
|
||||||
|
|
||||||
var assert = require('assert')
|
|
||||||
var appendField = require('../')
|
|
||||||
var testData = require('testdata-w3c-json-form')
|
|
||||||
|
|
||||||
describe('Append Field', function () {
|
|
||||||
for (var test of testData) {
|
|
||||||
it('handles ' + test.name, function () {
|
|
||||||
var store = Object.create(null)
|
|
||||||
|
|
||||||
for (var field of test.fields) {
|
|
||||||
appendField(store, field.key, field.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.deepEqual(store, test.expected)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2016, 2018 Linus Unnebäck
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,72 +0,0 @@
|
|||||||
/* eslint-disable node/no-deprecated-api */
|
|
||||||
|
|
||||||
var toString = Object.prototype.toString
|
|
||||||
|
|
||||||
var isModern = (
|
|
||||||
typeof Buffer !== 'undefined' &&
|
|
||||||
typeof Buffer.alloc === 'function' &&
|
|
||||||
typeof Buffer.allocUnsafe === 'function' &&
|
|
||||||
typeof Buffer.from === 'function'
|
|
||||||
)
|
|
||||||
|
|
||||||
function isArrayBuffer (input) {
|
|
||||||
return toString.call(input).slice(8, -1) === 'ArrayBuffer'
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromArrayBuffer (obj, byteOffset, length) {
|
|
||||||
byteOffset >>>= 0
|
|
||||||
|
|
||||||
var maxLength = obj.byteLength - byteOffset
|
|
||||||
|
|
||||||
if (maxLength < 0) {
|
|
||||||
throw new RangeError("'offset' is out of bounds")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length === undefined) {
|
|
||||||
length = maxLength
|
|
||||||
} else {
|
|
||||||
length >>>= 0
|
|
||||||
|
|
||||||
if (length > maxLength) {
|
|
||||||
throw new RangeError("'length' is out of bounds")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isModern
|
|
||||||
? Buffer.from(obj.slice(byteOffset, byteOffset + length))
|
|
||||||
: new Buffer(new Uint8Array(obj.slice(byteOffset, byteOffset + length)))
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromString (string, encoding) {
|
|
||||||
if (typeof encoding !== 'string' || encoding === '') {
|
|
||||||
encoding = 'utf8'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Buffer.isEncoding(encoding)) {
|
|
||||||
throw new TypeError('"encoding" must be a valid string encoding')
|
|
||||||
}
|
|
||||||
|
|
||||||
return isModern
|
|
||||||
? Buffer.from(string, encoding)
|
|
||||||
: new Buffer(string, encoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
function bufferFrom (value, encodingOrOffset, length) {
|
|
||||||
if (typeof value === 'number') {
|
|
||||||
throw new TypeError('"value" argument must not be a number')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isArrayBuffer(value)) {
|
|
||||||
return fromArrayBuffer(value, encodingOrOffset, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return fromString(value, encodingOrOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
return isModern
|
|
||||||
? Buffer.from(value)
|
|
||||||
: new Buffer(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = bufferFrom
|
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "buffer-from",
|
|
||||||
"version": "1.1.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": "LinusU/buffer-from",
|
|
||||||
"files": [
|
|
||||||
"index.js"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"test": "standard && node test"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"standard": "^12.0.1"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"buffer",
|
|
||||||
"buffer from"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
# Buffer From
|
|
||||||
|
|
||||||
A [ponyfill](https://ponyfill.com) for `Buffer.from`, uses native implementation if available.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm install --save buffer-from
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
const bufferFrom = require('buffer-from')
|
|
||||||
|
|
||||||
console.log(bufferFrom([1, 2, 3, 4]))
|
|
||||||
//=> <Buffer 01 02 03 04>
|
|
||||||
|
|
||||||
const arr = new Uint8Array([1, 2, 3, 4])
|
|
||||||
console.log(bufferFrom(arr.buffer, 1, 2))
|
|
||||||
//=> <Buffer 02 03>
|
|
||||||
|
|
||||||
console.log(bufferFrom('test', 'utf8'))
|
|
||||||
//=> <Buffer 74 65 73 74>
|
|
||||||
|
|
||||||
const buf = bufferFrom('test')
|
|
||||||
console.log(bufferFrom(buf))
|
|
||||||
//=> <Buffer 74 65 73 74>
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
### bufferFrom(array)
|
|
||||||
|
|
||||||
- `array` <Array>
|
|
||||||
|
|
||||||
Allocates a new `Buffer` using an `array` of octets.
|
|
||||||
|
|
||||||
### bufferFrom(arrayBuffer[, byteOffset[, length]])
|
|
||||||
|
|
||||||
- `arrayBuffer` <ArrayBuffer> The `.buffer` property of a TypedArray or ArrayBuffer
|
|
||||||
- `byteOffset` <Integer> Where to start copying from `arrayBuffer`. **Default:** `0`
|
|
||||||
- `length` <Integer> How many bytes to copy from `arrayBuffer`. **Default:** `arrayBuffer.length - byteOffset`
|
|
||||||
|
|
||||||
When passed a reference to the `.buffer` property of a TypedArray instance, the
|
|
||||||
newly created `Buffer` will share the same allocated memory as the TypedArray.
|
|
||||||
|
|
||||||
The optional `byteOffset` and `length` arguments specify a memory range within
|
|
||||||
the `arrayBuffer` that will be shared by the `Buffer`.
|
|
||||||
|
|
||||||
### bufferFrom(buffer)
|
|
||||||
|
|
||||||
- `buffer` <Buffer> An existing `Buffer` to copy data from
|
|
||||||
|
|
||||||
Copies the passed `buffer` data onto a new `Buffer` instance.
|
|
||||||
|
|
||||||
### bufferFrom(string[, encoding])
|
|
||||||
|
|
||||||
- `string` <String> A string to encode.
|
|
||||||
- `encoding` <String> The encoding of `string`. **Default:** `'utf8'`
|
|
||||||
|
|
||||||
Creates a new `Buffer` containing the given JavaScript string `string`. If
|
|
||||||
provided, the `encoding` parameter identifies the character encoding of
|
|
||||||
`string`.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [buffer-alloc](https://github.com/LinusU/buffer-alloc) A ponyfill for `Buffer.alloc`
|
|
||||||
- [buffer-alloc-unsafe](https://github.com/LinusU/buffer-alloc-unsafe) A ponyfill for `Buffer.allocUnsafe`
|
|
@ -1,5 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
extends: '@mscdex/eslint-config',
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
tests-linux:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node-version: [10.16.0, 10.x, 12.x, 14.x, 16.x]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- name: Install module
|
|
||||||
run: npm install
|
|
||||||
- name: Run tests
|
|
||||||
run: npm test
|
|
@ -1,23 +0,0 @@
|
|||||||
name: lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: 16.x
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint-js:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ env.NODE_VERSION }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- name: Install ESLint + ESLint configs/plugins
|
|
||||||
run: npm install --only=dev
|
|
||||||
- name: Lint files
|
|
||||||
run: npm run lint
|
|
@ -1,19 +0,0 @@
|
|||||||
Copyright Brian White. All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to
|
|
||||||
deal in the Software without restriction, including without limitation the
|
|
||||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
IN THE SOFTWARE.
|
|
@ -1,191 +0,0 @@
|
|||||||
# Description
|
|
||||||
|
|
||||||
A node.js module for parsing incoming HTML form data.
|
|
||||||
|
|
||||||
Changes (breaking or otherwise) in v1.0.0 can be found [here](https://github.com/mscdex/busboy/issues/266).
|
|
||||||
|
|
||||||
# Requirements
|
|
||||||
|
|
||||||
* [node.js](http://nodejs.org/) -- v10.16.0 or newer
|
|
||||||
|
|
||||||
|
|
||||||
# Install
|
|
||||||
|
|
||||||
npm install busboy
|
|
||||||
|
|
||||||
|
|
||||||
# Examples
|
|
||||||
|
|
||||||
* Parsing (multipart) with default options:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const http = require('http');
|
|
||||||
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
http.createServer((req, res) => {
|
|
||||||
if (req.method === 'POST') {
|
|
||||||
console.log('POST request');
|
|
||||||
const bb = busboy({ headers: req.headers });
|
|
||||||
bb.on('file', (name, file, info) => {
|
|
||||||
const { filename, encoding, mimeType } = info;
|
|
||||||
console.log(
|
|
||||||
`File [${name}]: filename: %j, encoding: %j, mimeType: %j`,
|
|
||||||
filename,
|
|
||||||
encoding,
|
|
||||||
mimeType
|
|
||||||
);
|
|
||||||
file.on('data', (data) => {
|
|
||||||
console.log(`File [${name}] got ${data.length} bytes`);
|
|
||||||
}).on('close', () => {
|
|
||||||
console.log(`File [${name}] done`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
bb.on('field', (name, val, info) => {
|
|
||||||
console.log(`Field [${name}]: value: %j`, val);
|
|
||||||
});
|
|
||||||
bb.on('close', () => {
|
|
||||||
console.log('Done parsing form!');
|
|
||||||
res.writeHead(303, { Connection: 'close', Location: '/' });
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
req.pipe(bb);
|
|
||||||
} else if (req.method === 'GET') {
|
|
||||||
res.writeHead(200, { Connection: 'close' });
|
|
||||||
res.end(`
|
|
||||||
<html>
|
|
||||||
<head></head>
|
|
||||||
<body>
|
|
||||||
<form method="POST" enctype="multipart/form-data">
|
|
||||||
<input type="file" name="filefield"><br />
|
|
||||||
<input type="text" name="textfield"><br />
|
|
||||||
<input type="submit">
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
}).listen(8000, () => {
|
|
||||||
console.log('Listening for requests');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example output:
|
|
||||||
//
|
|
||||||
// Listening for requests
|
|
||||||
// < ... form submitted ... >
|
|
||||||
// POST request
|
|
||||||
// File [filefield]: filename: "logo.jpg", encoding: "binary", mime: "image/jpeg"
|
|
||||||
// File [filefield] got 11912 bytes
|
|
||||||
// Field [textfield]: value: "testing! :-)"
|
|
||||||
// File [filefield] done
|
|
||||||
// Done parsing form!
|
|
||||||
```
|
|
||||||
|
|
||||||
* Save all incoming files to disk:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const { randomFillSync } = require('crypto');
|
|
||||||
const fs = require('fs');
|
|
||||||
const http = require('http');
|
|
||||||
const os = require('os');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
const random = (() => {
|
|
||||||
const buf = Buffer.alloc(16);
|
|
||||||
return () => randomFillSync(buf).toString('hex');
|
|
||||||
})();
|
|
||||||
|
|
||||||
http.createServer((req, res) => {
|
|
||||||
if (req.method === 'POST') {
|
|
||||||
const bb = busboy({ headers: req.headers });
|
|
||||||
bb.on('file', (name, file, info) => {
|
|
||||||
const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`);
|
|
||||||
file.pipe(fs.createWriteStream(saveTo));
|
|
||||||
});
|
|
||||||
bb.on('close', () => {
|
|
||||||
res.writeHead(200, { 'Connection': 'close' });
|
|
||||||
res.end(`That's all folks!`);
|
|
||||||
});
|
|
||||||
req.pipe(bb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.writeHead(404);
|
|
||||||
res.end();
|
|
||||||
}).listen(8000, () => {
|
|
||||||
console.log('Listening for requests');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# API
|
|
||||||
|
|
||||||
## Exports
|
|
||||||
|
|
||||||
`busboy` exports a single function:
|
|
||||||
|
|
||||||
**( _function_ )**(< _object_ >config) - Creates and returns a new _Writable_ form parser stream.
|
|
||||||
|
|
||||||
* Valid `config` properties:
|
|
||||||
|
|
||||||
* **headers** - _object_ - These are the HTTP headers of the incoming request, which are used by individual parsers.
|
|
||||||
|
|
||||||
* **highWaterMark** - _integer_ - highWaterMark to use for the parser stream. **Default:** node's _stream.Writable_ default.
|
|
||||||
|
|
||||||
* **fileHwm** - _integer_ - highWaterMark to use for individual file streams. **Default:** node's _stream.Readable_ default.
|
|
||||||
|
|
||||||
* **defCharset** - _string_ - Default character set to use when one isn't defined. **Default:** `'utf8'`.
|
|
||||||
|
|
||||||
* **defParamCharset** - _string_ - For multipart forms, the default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). **Default:** `'latin1'`.
|
|
||||||
|
|
||||||
* **preservePath** - _boolean_ - If paths in filenames from file parts in a `'multipart/form-data'` request shall be preserved. **Default:** `false`.
|
|
||||||
|
|
||||||
* **limits** - _object_ - Various limits on incoming data. Valid properties are:
|
|
||||||
|
|
||||||
* **fieldNameSize** - _integer_ - Max field name size (in bytes). **Default:** `100`.
|
|
||||||
|
|
||||||
* **fieldSize** - _integer_ - Max field value size (in bytes). **Default:** `1048576` (1MB).
|
|
||||||
|
|
||||||
* **fields** - _integer_ - Max number of non-file fields. **Default:** `Infinity`.
|
|
||||||
|
|
||||||
* **fileSize** - _integer_ - For multipart forms, the max file size (in bytes). **Default:** `Infinity`.
|
|
||||||
|
|
||||||
* **files** - _integer_ - For multipart forms, the max number of file fields. **Default:** `Infinity`.
|
|
||||||
|
|
||||||
* **parts** - _integer_ - For multipart forms, the max number of parts (fields + files). **Default:** `Infinity`.
|
|
||||||
|
|
||||||
* **headerPairs** - _integer_ - For multipart forms, the max number of header key-value pairs to parse. **Default:** `2000` (same as node's http module).
|
|
||||||
|
|
||||||
This function can throw exceptions if there is something wrong with the values in `config`. For example, if the Content-Type in `headers` is missing entirely, is not a supported type, or is missing the boundary for `'multipart/form-data'` requests.
|
|
||||||
|
|
||||||
## (Special) Parser stream events
|
|
||||||
|
|
||||||
* **file**(< _string_ >name, < _Readable_ >stream, < _object_ >info) - Emitted for each new file found. `name` contains the form field name. `stream` is a _Readable_ stream containing the file's data. No transformations/conversions (e.g. base64 to raw binary) are done on the file's data. `info` contains the following properties:
|
|
||||||
|
|
||||||
* `filename` - _string_ - If supplied, this contains the file's filename. **WARNING:** You should almost _never_ use this value as-is (especially if you are using `preservePath: true` in your `config`) as it could contain malicious input. You are better off generating your own (safe) filenames, or at the very least using a hash of the filename.
|
|
||||||
|
|
||||||
* `encoding` - _string_ - The file's `'Content-Transfer-Encoding'` value.
|
|
||||||
|
|
||||||
* `mimeType` - _string_ - The file's `'Content-Type'` value.
|
|
||||||
|
|
||||||
**Note:** If you listen for this event, you should always consume the `stream` whether you care about its contents or not (you can simply do `stream.resume();` if you want to discard/skip the contents), otherwise the `'finish'`/`'close'` event will never fire on the busboy parser stream.
|
|
||||||
However, if you aren't accepting files, you can either simply not listen for the `'file'` event at all or set `limits.files` to `0`, and any/all files will be automatically skipped (these skipped files will still count towards any configured `limits.files` and `limits.parts` limits though).
|
|
||||||
|
|
||||||
**Note:** If a configured `limits.fileSize` limit was reached for a file, `stream` will both have a boolean property `truncated` set to `true` (best checked at the end of the stream) and emit a `'limit'` event to notify you when this happens.
|
|
||||||
|
|
||||||
* **field**(< _string_ >name, < _string_ >value, < _object_ >info) - Emitted for each new non-file field found. `name` contains the form field name. `value` contains the string value of the field. `info` contains the following properties:
|
|
||||||
|
|
||||||
* `nameTruncated` - _boolean_ - Whether `name` was truncated or not (due to a configured `limits.fieldNameSize` limit)
|
|
||||||
|
|
||||||
* `valueTruncated` - _boolean_ - Whether `value` was truncated or not (due to a configured `limits.fieldSize` limit)
|
|
||||||
|
|
||||||
* `encoding` - _string_ - The field's `'Content-Transfer-Encoding'` value.
|
|
||||||
|
|
||||||
* `mimeType` - _string_ - The field's `'Content-Type'` value.
|
|
||||||
|
|
||||||
* **partsLimit**() - Emitted when the configured `limits.parts` limit has been reached. No more `'file'` or `'field'` events will be emitted.
|
|
||||||
|
|
||||||
* **filesLimit**() - Emitted when the configured `limits.files` limit has been reached. No more `'file'` events will be emitted.
|
|
||||||
|
|
||||||
* **fieldsLimit**() - Emitted when the configured `limits.fields` limit has been reached. No more `'field'` events will be emitted.
|
|
@ -1,149 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
function createMultipartBuffers(boundary, sizes) {
|
|
||||||
const bufs = [];
|
|
||||||
for (let i = 0; i < sizes.length; ++i) {
|
|
||||||
const mb = sizes[i] * 1024 * 1024;
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}`,
|
|
||||||
`content-disposition: form-data; name="field${i + 1}"`,
|
|
||||||
'',
|
|
||||||
'0'.repeat(mb),
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
}
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}--`,
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
return bufs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boundary = '-----------------------------168072824752491622650073';
|
|
||||||
const buffers = createMultipartBuffers(boundary, [
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
20,
|
|
||||||
50,
|
|
||||||
]);
|
|
||||||
const calls = {
|
|
||||||
partBegin: 0,
|
|
||||||
headerField: 0,
|
|
||||||
headerValue: 0,
|
|
||||||
headerEnd: 0,
|
|
||||||
headersEnd: 0,
|
|
||||||
partData: 0,
|
|
||||||
partEnd: 0,
|
|
||||||
end: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const moduleName = process.argv[2];
|
|
||||||
switch (moduleName) {
|
|
||||||
case 'busboy': {
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
const parser = busboy({
|
|
||||||
limits: {
|
|
||||||
fieldSizeLimit: Infinity,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
parser.on('field', (name, val, info) => {
|
|
||||||
++calls.partBegin;
|
|
||||||
++calls.partData;
|
|
||||||
++calls.partEnd;
|
|
||||||
}).on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable': {
|
|
||||||
const { MultipartParser } = require('formidable');
|
|
||||||
|
|
||||||
const parser = new MultipartParser();
|
|
||||||
parser.initWithBoundary(boundary);
|
|
||||||
parser.on('data', ({ name }) => {
|
|
||||||
++calls[name];
|
|
||||||
if (name === 'end')
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'multiparty': {
|
|
||||||
const { Readable } = require('stream');
|
|
||||||
|
|
||||||
const { Form } = require('multiparty');
|
|
||||||
|
|
||||||
const form = new Form({
|
|
||||||
maxFieldsSize: Infinity,
|
|
||||||
maxFields: Infinity,
|
|
||||||
maxFilesSize: Infinity,
|
|
||||||
autoFields: false,
|
|
||||||
autoFiles: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = new Readable({ read: () => {} });
|
|
||||||
req.headers = {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
function hijack(name, fn) {
|
|
||||||
const oldFn = form[name];
|
|
||||||
form[name] = function() {
|
|
||||||
fn();
|
|
||||||
return oldFn.apply(this, arguments);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
hijack('onParseHeaderField', () => {
|
|
||||||
++calls.headerField;
|
|
||||||
});
|
|
||||||
hijack('onParseHeaderValue', () => {
|
|
||||||
++calls.headerValue;
|
|
||||||
});
|
|
||||||
hijack('onParsePartBegin', () => {
|
|
||||||
++calls.partBegin;
|
|
||||||
});
|
|
||||||
hijack('onParsePartData', () => {
|
|
||||||
++calls.partData;
|
|
||||||
});
|
|
||||||
hijack('onParsePartEnd', () => {
|
|
||||||
++calls.partEnd;
|
|
||||||
});
|
|
||||||
|
|
||||||
form.on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
}).on('part', (p) => p.resume());
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
form.parse(req);
|
|
||||||
for (const buf of buffers)
|
|
||||||
req.push(buf);
|
|
||||||
req.push(null);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (moduleName === undefined)
|
|
||||||
console.error('Missing parser module name');
|
|
||||||
else
|
|
||||||
console.error(`Invalid parser module name: ${moduleName}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
function createMultipartBuffers(boundary, sizes) {
|
|
||||||
const bufs = [];
|
|
||||||
for (let i = 0; i < sizes.length; ++i) {
|
|
||||||
const mb = sizes[i] * 1024 * 1024;
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}`,
|
|
||||||
`content-disposition: form-data; name="field${i + 1}"`,
|
|
||||||
'',
|
|
||||||
'0'.repeat(mb),
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
}
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}--`,
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
return bufs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boundary = '-----------------------------168072824752491622650073';
|
|
||||||
const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
|
|
||||||
const calls = {
|
|
||||||
partBegin: 0,
|
|
||||||
headerField: 0,
|
|
||||||
headerValue: 0,
|
|
||||||
headerEnd: 0,
|
|
||||||
headersEnd: 0,
|
|
||||||
partData: 0,
|
|
||||||
partEnd: 0,
|
|
||||||
end: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const moduleName = process.argv[2];
|
|
||||||
switch (moduleName) {
|
|
||||||
case 'busboy': {
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
const parser = busboy({
|
|
||||||
limits: {
|
|
||||||
fieldSizeLimit: Infinity,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
parser.on('field', (name, val, info) => {
|
|
||||||
++calls.partBegin;
|
|
||||||
++calls.partData;
|
|
||||||
++calls.partEnd;
|
|
||||||
}).on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable': {
|
|
||||||
const { MultipartParser } = require('formidable');
|
|
||||||
|
|
||||||
const parser = new MultipartParser();
|
|
||||||
parser.initWithBoundary(boundary);
|
|
||||||
parser.on('data', ({ name }) => {
|
|
||||||
++calls[name];
|
|
||||||
if (name === 'end')
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'multiparty': {
|
|
||||||
const { Readable } = require('stream');
|
|
||||||
|
|
||||||
const { Form } = require('multiparty');
|
|
||||||
|
|
||||||
const form = new Form({
|
|
||||||
maxFieldsSize: Infinity,
|
|
||||||
maxFields: Infinity,
|
|
||||||
maxFilesSize: Infinity,
|
|
||||||
autoFields: false,
|
|
||||||
autoFiles: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = new Readable({ read: () => {} });
|
|
||||||
req.headers = {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
function hijack(name, fn) {
|
|
||||||
const oldFn = form[name];
|
|
||||||
form[name] = function() {
|
|
||||||
fn();
|
|
||||||
return oldFn.apply(this, arguments);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
hijack('onParseHeaderField', () => {
|
|
||||||
++calls.headerField;
|
|
||||||
});
|
|
||||||
hijack('onParseHeaderValue', () => {
|
|
||||||
++calls.headerValue;
|
|
||||||
});
|
|
||||||
hijack('onParsePartBegin', () => {
|
|
||||||
++calls.partBegin;
|
|
||||||
});
|
|
||||||
hijack('onParsePartData', () => {
|
|
||||||
++calls.partData;
|
|
||||||
});
|
|
||||||
hijack('onParsePartEnd', () => {
|
|
||||||
++calls.partEnd;
|
|
||||||
});
|
|
||||||
|
|
||||||
form.on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
}).on('part', (p) => p.resume());
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
form.parse(req);
|
|
||||||
for (const buf of buffers)
|
|
||||||
req.push(buf);
|
|
||||||
req.push(null);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (moduleName === undefined)
|
|
||||||
console.error('Missing parser module name');
|
|
||||||
else
|
|
||||||
console.error(`Invalid parser module name: ${moduleName}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
@ -1,154 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
function createMultipartBuffers(boundary, sizes) {
|
|
||||||
const bufs = [];
|
|
||||||
for (let i = 0; i < sizes.length; ++i) {
|
|
||||||
const mb = sizes[i] * 1024 * 1024;
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}`,
|
|
||||||
`content-disposition: form-data; name="file${i + 1}"; `
|
|
||||||
+ `filename="random${i + 1}.bin"`,
|
|
||||||
'content-type: application/octet-stream',
|
|
||||||
'',
|
|
||||||
'0'.repeat(mb),
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
}
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}--`,
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
return bufs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boundary = '-----------------------------168072824752491622650073';
|
|
||||||
const buffers = createMultipartBuffers(boundary, [
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
20,
|
|
||||||
50,
|
|
||||||
]);
|
|
||||||
const calls = {
|
|
||||||
partBegin: 0,
|
|
||||||
headerField: 0,
|
|
||||||
headerValue: 0,
|
|
||||||
headerEnd: 0,
|
|
||||||
headersEnd: 0,
|
|
||||||
partData: 0,
|
|
||||||
partEnd: 0,
|
|
||||||
end: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const moduleName = process.argv[2];
|
|
||||||
switch (moduleName) {
|
|
||||||
case 'busboy': {
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
const parser = busboy({
|
|
||||||
limits: {
|
|
||||||
fieldSizeLimit: Infinity,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
parser.on('file', (name, stream, info) => {
|
|
||||||
++calls.partBegin;
|
|
||||||
stream.on('data', (chunk) => {
|
|
||||||
++calls.partData;
|
|
||||||
}).on('end', () => {
|
|
||||||
++calls.partEnd;
|
|
||||||
});
|
|
||||||
}).on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable': {
|
|
||||||
const { MultipartParser } = require('formidable');
|
|
||||||
|
|
||||||
const parser = new MultipartParser();
|
|
||||||
parser.initWithBoundary(boundary);
|
|
||||||
parser.on('data', ({ name }) => {
|
|
||||||
++calls[name];
|
|
||||||
if (name === 'end')
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'multiparty': {
|
|
||||||
const { Readable } = require('stream');
|
|
||||||
|
|
||||||
const { Form } = require('multiparty');
|
|
||||||
|
|
||||||
const form = new Form({
|
|
||||||
maxFieldsSize: Infinity,
|
|
||||||
maxFields: Infinity,
|
|
||||||
maxFilesSize: Infinity,
|
|
||||||
autoFields: false,
|
|
||||||
autoFiles: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = new Readable({ read: () => {} });
|
|
||||||
req.headers = {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
function hijack(name, fn) {
|
|
||||||
const oldFn = form[name];
|
|
||||||
form[name] = function() {
|
|
||||||
fn();
|
|
||||||
return oldFn.apply(this, arguments);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
hijack('onParseHeaderField', () => {
|
|
||||||
++calls.headerField;
|
|
||||||
});
|
|
||||||
hijack('onParseHeaderValue', () => {
|
|
||||||
++calls.headerValue;
|
|
||||||
});
|
|
||||||
hijack('onParsePartBegin', () => {
|
|
||||||
++calls.partBegin;
|
|
||||||
});
|
|
||||||
hijack('onParsePartData', () => {
|
|
||||||
++calls.partData;
|
|
||||||
});
|
|
||||||
hijack('onParsePartEnd', () => {
|
|
||||||
++calls.partEnd;
|
|
||||||
});
|
|
||||||
|
|
||||||
form.on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
}).on('part', (p) => p.resume());
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
form.parse(req);
|
|
||||||
for (const buf of buffers)
|
|
||||||
req.push(buf);
|
|
||||||
req.push(null);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (moduleName === undefined)
|
|
||||||
console.error('Missing parser module name');
|
|
||||||
else
|
|
||||||
console.error(`Invalid parser module name: ${moduleName}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
function createMultipartBuffers(boundary, sizes) {
|
|
||||||
const bufs = [];
|
|
||||||
for (let i = 0; i < sizes.length; ++i) {
|
|
||||||
const mb = sizes[i] * 1024 * 1024;
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}`,
|
|
||||||
`content-disposition: form-data; name="file${i + 1}"; `
|
|
||||||
+ `filename="random${i + 1}.bin"`,
|
|
||||||
'content-type: application/octet-stream',
|
|
||||||
'',
|
|
||||||
'0'.repeat(mb),
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
}
|
|
||||||
bufs.push(Buffer.from([
|
|
||||||
`--${boundary}--`,
|
|
||||||
'',
|
|
||||||
].join('\r\n')));
|
|
||||||
return bufs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boundary = '-----------------------------168072824752491622650073';
|
|
||||||
const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
|
|
||||||
const calls = {
|
|
||||||
partBegin: 0,
|
|
||||||
headerField: 0,
|
|
||||||
headerValue: 0,
|
|
||||||
headerEnd: 0,
|
|
||||||
headersEnd: 0,
|
|
||||||
partData: 0,
|
|
||||||
partEnd: 0,
|
|
||||||
end: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const moduleName = process.argv[2];
|
|
||||||
switch (moduleName) {
|
|
||||||
case 'busboy': {
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
const parser = busboy({
|
|
||||||
limits: {
|
|
||||||
fieldSizeLimit: Infinity,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
parser.on('file', (name, stream, info) => {
|
|
||||||
++calls.partBegin;
|
|
||||||
stream.on('data', (chunk) => {
|
|
||||||
++calls.partData;
|
|
||||||
}).on('end', () => {
|
|
||||||
++calls.partEnd;
|
|
||||||
});
|
|
||||||
}).on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable': {
|
|
||||||
const { MultipartParser } = require('formidable');
|
|
||||||
|
|
||||||
const parser = new MultipartParser();
|
|
||||||
parser.initWithBoundary(boundary);
|
|
||||||
parser.on('data', ({ name }) => {
|
|
||||||
++calls[name];
|
|
||||||
if (name === 'end')
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'multiparty': {
|
|
||||||
const { Readable } = require('stream');
|
|
||||||
|
|
||||||
const { Form } = require('multiparty');
|
|
||||||
|
|
||||||
const form = new Form({
|
|
||||||
maxFieldsSize: Infinity,
|
|
||||||
maxFields: Infinity,
|
|
||||||
maxFilesSize: Infinity,
|
|
||||||
autoFields: false,
|
|
||||||
autoFiles: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = new Readable({ read: () => {} });
|
|
||||||
req.headers = {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
function hijack(name, fn) {
|
|
||||||
const oldFn = form[name];
|
|
||||||
form[name] = function() {
|
|
||||||
fn();
|
|
||||||
return oldFn.apply(this, arguments);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
hijack('onParseHeaderField', () => {
|
|
||||||
++calls.headerField;
|
|
||||||
});
|
|
||||||
hijack('onParseHeaderValue', () => {
|
|
||||||
++calls.headerValue;
|
|
||||||
});
|
|
||||||
hijack('onParsePartBegin', () => {
|
|
||||||
++calls.partBegin;
|
|
||||||
});
|
|
||||||
hijack('onParsePartData', () => {
|
|
||||||
++calls.partData;
|
|
||||||
});
|
|
||||||
hijack('onParsePartEnd', () => {
|
|
||||||
++calls.partEnd;
|
|
||||||
});
|
|
||||||
|
|
||||||
form.on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
}).on('part', (p) => p.resume());
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
form.parse(req);
|
|
||||||
for (const buf of buffers)
|
|
||||||
req.push(buf);
|
|
||||||
req.push(null);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (moduleName === undefined)
|
|
||||||
console.error('Missing parser module name');
|
|
||||||
else
|
|
||||||
console.error(`Invalid parser module name: ${moduleName}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const buffers = [
|
|
||||||
Buffer.from(
|
|
||||||
(new Array(100)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const calls = {
|
|
||||||
field: 0,
|
|
||||||
end: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let n = 3e3;
|
|
||||||
|
|
||||||
const moduleName = process.argv[2];
|
|
||||||
switch (moduleName) {
|
|
||||||
case 'busboy': {
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
(function next() {
|
|
||||||
const parser = busboy({
|
|
||||||
limits: {
|
|
||||||
fieldSizeLimit: Infinity,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
parser.on('field', (name, val, info) => {
|
|
||||||
++calls.field;
|
|
||||||
}).on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
if (--n === 0)
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
else
|
|
||||||
process.nextTick(next);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
parser.end();
|
|
||||||
})();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable': {
|
|
||||||
const QuerystringParser =
|
|
||||||
require('formidable/src/parsers/Querystring.js');
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
(function next() {
|
|
||||||
const parser = new QuerystringParser();
|
|
||||||
parser.on('data', (obj) => {
|
|
||||||
++calls.field;
|
|
||||||
}).on('end', () => {
|
|
||||||
++calls.end;
|
|
||||||
if (--n === 0)
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
else
|
|
||||||
process.nextTick(next);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
parser.end();
|
|
||||||
})();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable-streaming': {
|
|
||||||
const QuerystringParser =
|
|
||||||
require('formidable/src/parsers/StreamingQuerystring.js');
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
(function next() {
|
|
||||||
const parser = new QuerystringParser();
|
|
||||||
parser.on('data', (obj) => {
|
|
||||||
++calls.field;
|
|
||||||
}).on('end', () => {
|
|
||||||
++calls.end;
|
|
||||||
if (--n === 0)
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
else
|
|
||||||
process.nextTick(next);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
parser.end();
|
|
||||||
})();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (moduleName === undefined)
|
|
||||||
console.error('Missing parser module name');
|
|
||||||
else
|
|
||||||
console.error(`Invalid parser module name: ${moduleName}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const buffers = [
|
|
||||||
Buffer.from(
|
|
||||||
(new Array(900)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const calls = {
|
|
||||||
field: 0,
|
|
||||||
end: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const moduleName = process.argv[2];
|
|
||||||
switch (moduleName) {
|
|
||||||
case 'busboy': {
|
|
||||||
const busboy = require('busboy');
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
const parser = busboy({
|
|
||||||
limits: {
|
|
||||||
fieldSizeLimit: Infinity,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
parser.on('field', (name, val, info) => {
|
|
||||||
++calls.field;
|
|
||||||
}).on('close', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
parser.end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable': {
|
|
||||||
const QuerystringParser =
|
|
||||||
require('formidable/src/parsers/Querystring.js');
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
const parser = new QuerystringParser();
|
|
||||||
parser.on('data', (obj) => {
|
|
||||||
++calls.field;
|
|
||||||
}).on('end', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
parser.end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'formidable-streaming': {
|
|
||||||
const QuerystringParser =
|
|
||||||
require('formidable/src/parsers/StreamingQuerystring.js');
|
|
||||||
|
|
||||||
console.time(moduleName);
|
|
||||||
const parser = new QuerystringParser();
|
|
||||||
parser.on('data', (obj) => {
|
|
||||||
++calls.field;
|
|
||||||
}).on('end', () => {
|
|
||||||
++calls.end;
|
|
||||||
console.timeEnd(moduleName);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const buf of buffers)
|
|
||||||
parser.write(buf);
|
|
||||||
parser.end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (moduleName === undefined)
|
|
||||||
console.error('Missing parser module name');
|
|
||||||
else
|
|
||||||
console.error(`Invalid parser module name: ${moduleName}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { parseContentType } = require('./utils.js');
|
|
||||||
|
|
||||||
function getInstance(cfg) {
|
|
||||||
const headers = cfg.headers;
|
|
||||||
const conType = parseContentType(headers['content-type']);
|
|
||||||
if (!conType)
|
|
||||||
throw new Error('Malformed content type');
|
|
||||||
|
|
||||||
for (const type of TYPES) {
|
|
||||||
const matched = type.detect(conType);
|
|
||||||
if (!matched)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const instanceCfg = {
|
|
||||||
limits: cfg.limits,
|
|
||||||
headers,
|
|
||||||
conType,
|
|
||||||
highWaterMark: undefined,
|
|
||||||
fileHwm: undefined,
|
|
||||||
defCharset: undefined,
|
|
||||||
defParamCharset: undefined,
|
|
||||||
preservePath: false,
|
|
||||||
};
|
|
||||||
if (cfg.highWaterMark)
|
|
||||||
instanceCfg.highWaterMark = cfg.highWaterMark;
|
|
||||||
if (cfg.fileHwm)
|
|
||||||
instanceCfg.fileHwm = cfg.fileHwm;
|
|
||||||
instanceCfg.defCharset = cfg.defCharset;
|
|
||||||
instanceCfg.defParamCharset = cfg.defParamCharset;
|
|
||||||
instanceCfg.preservePath = cfg.preservePath;
|
|
||||||
return new type(instanceCfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Unsupported content type: ${headers['content-type']}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: types are explicitly listed here for easier bundling
|
|
||||||
// See: https://github.com/mscdex/busboy/issues/121
|
|
||||||
const TYPES = [
|
|
||||||
require('./types/multipart'),
|
|
||||||
require('./types/urlencoded'),
|
|
||||||
].filter(function(typemod) { return typeof typemod.detect === 'function'; });
|
|
||||||
|
|
||||||
module.exports = (cfg) => {
|
|
||||||
if (typeof cfg !== 'object' || cfg === null)
|
|
||||||
cfg = {};
|
|
||||||
|
|
||||||
if (typeof cfg.headers !== 'object'
|
|
||||||
|| cfg.headers === null
|
|
||||||
|| typeof cfg.headers['content-type'] !== 'string') {
|
|
||||||
throw new Error('Missing Content-Type');
|
|
||||||
}
|
|
||||||
|
|
||||||
return getInstance(cfg);
|
|
||||||
};
|
|
@ -1,653 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { Readable, Writable } = require('stream');
|
|
||||||
|
|
||||||
const StreamSearch = require('streamsearch');
|
|
||||||
|
|
||||||
const {
|
|
||||||
basename,
|
|
||||||
convertToUTF8,
|
|
||||||
getDecoder,
|
|
||||||
parseContentType,
|
|
||||||
parseDisposition,
|
|
||||||
} = require('../utils.js');
|
|
||||||
|
|
||||||
const BUF_CRLF = Buffer.from('\r\n');
|
|
||||||
const BUF_CR = Buffer.from('\r');
|
|
||||||
const BUF_DASH = Buffer.from('-');
|
|
||||||
|
|
||||||
function noop() {}
|
|
||||||
|
|
||||||
const MAX_HEADER_PAIRS = 2000; // From node
|
|
||||||
const MAX_HEADER_SIZE = 16 * 1024; // From node (its default value)
|
|
||||||
|
|
||||||
const HPARSER_NAME = 0;
|
|
||||||
const HPARSER_PRE_OWS = 1;
|
|
||||||
const HPARSER_VALUE = 2;
|
|
||||||
class HeaderParser {
|
|
||||||
constructor(cb) {
|
|
||||||
this.header = Object.create(null);
|
|
||||||
this.pairCount = 0;
|
|
||||||
this.byteCount = 0;
|
|
||||||
this.state = HPARSER_NAME;
|
|
||||||
this.name = '';
|
|
||||||
this.value = '';
|
|
||||||
this.crlf = 0;
|
|
||||||
this.cb = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.header = Object.create(null);
|
|
||||||
this.pairCount = 0;
|
|
||||||
this.byteCount = 0;
|
|
||||||
this.state = HPARSER_NAME;
|
|
||||||
this.name = '';
|
|
||||||
this.value = '';
|
|
||||||
this.crlf = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
push(chunk, pos, end) {
|
|
||||||
let start = pos;
|
|
||||||
while (pos < end) {
|
|
||||||
switch (this.state) {
|
|
||||||
case HPARSER_NAME: {
|
|
||||||
let done = false;
|
|
||||||
for (; pos < end; ++pos) {
|
|
||||||
if (this.byteCount === MAX_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
++this.byteCount;
|
|
||||||
const code = chunk[pos];
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
if (code !== 58/* ':' */)
|
|
||||||
return -1;
|
|
||||||
this.name += chunk.latin1Slice(start, pos);
|
|
||||||
if (this.name.length === 0)
|
|
||||||
return -1;
|
|
||||||
++pos;
|
|
||||||
done = true;
|
|
||||||
this.state = HPARSER_PRE_OWS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!done) {
|
|
||||||
this.name += chunk.latin1Slice(start, pos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// FALLTHROUGH
|
|
||||||
}
|
|
||||||
case HPARSER_PRE_OWS: {
|
|
||||||
// Skip optional whitespace
|
|
||||||
let done = false;
|
|
||||||
for (; pos < end; ++pos) {
|
|
||||||
if (this.byteCount === MAX_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
++this.byteCount;
|
|
||||||
const code = chunk[pos];
|
|
||||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */) {
|
|
||||||
start = pos;
|
|
||||||
done = true;
|
|
||||||
this.state = HPARSER_VALUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!done)
|
|
||||||
break;
|
|
||||||
// FALLTHROUGH
|
|
||||||
}
|
|
||||||
case HPARSER_VALUE:
|
|
||||||
switch (this.crlf) {
|
|
||||||
case 0: // Nothing yet
|
|
||||||
for (; pos < end; ++pos) {
|
|
||||||
if (this.byteCount === MAX_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
++this.byteCount;
|
|
||||||
const code = chunk[pos];
|
|
||||||
if (FIELD_VCHAR[code] !== 1) {
|
|
||||||
if (code !== 13/* '\r' */)
|
|
||||||
return -1;
|
|
||||||
++this.crlf;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.value += chunk.latin1Slice(start, pos++);
|
|
||||||
break;
|
|
||||||
case 1: // Received CR
|
|
||||||
if (this.byteCount === MAX_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
++this.byteCount;
|
|
||||||
if (chunk[pos++] !== 10/* '\n' */)
|
|
||||||
return -1;
|
|
||||||
++this.crlf;
|
|
||||||
break;
|
|
||||||
case 2: { // Received CR LF
|
|
||||||
if (this.byteCount === MAX_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
++this.byteCount;
|
|
||||||
const code = chunk[pos];
|
|
||||||
if (code === 32/* ' ' */ || code === 9/* '\t' */) {
|
|
||||||
// Folded value
|
|
||||||
start = pos;
|
|
||||||
this.crlf = 0;
|
|
||||||
} else {
|
|
||||||
if (++this.pairCount < MAX_HEADER_PAIRS) {
|
|
||||||
this.name = this.name.toLowerCase();
|
|
||||||
if (this.header[this.name] === undefined)
|
|
||||||
this.header[this.name] = [this.value];
|
|
||||||
else
|
|
||||||
this.header[this.name].push(this.value);
|
|
||||||
}
|
|
||||||
if (code === 13/* '\r' */) {
|
|
||||||
++this.crlf;
|
|
||||||
++pos;
|
|
||||||
} else {
|
|
||||||
// Assume start of next header field name
|
|
||||||
start = pos;
|
|
||||||
this.crlf = 0;
|
|
||||||
this.state = HPARSER_NAME;
|
|
||||||
this.name = '';
|
|
||||||
this.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: { // Received CR LF CR
|
|
||||||
if (this.byteCount === MAX_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
++this.byteCount;
|
|
||||||
if (chunk[pos++] !== 10/* '\n' */)
|
|
||||||
return -1;
|
|
||||||
// End of header
|
|
||||||
const header = this.header;
|
|
||||||
this.reset();
|
|
||||||
this.cb(header);
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FileStream extends Readable {
|
|
||||||
constructor(opts, owner) {
|
|
||||||
super(opts);
|
|
||||||
this.truncated = false;
|
|
||||||
this._readcb = null;
|
|
||||||
this.once('end', () => {
|
|
||||||
// We need to make sure that we call any outstanding _writecb() that is
|
|
||||||
// associated with this file so that processing of the rest of the form
|
|
||||||
// can continue. This may not happen if the file stream ends right after
|
|
||||||
// backpressure kicks in, so we force it here.
|
|
||||||
this._read();
|
|
||||||
if (--owner._fileEndsLeft === 0 && owner._finalcb) {
|
|
||||||
const cb = owner._finalcb;
|
|
||||||
owner._finalcb = null;
|
|
||||||
// Make sure other 'end' event handlers get a chance to be executed
|
|
||||||
// before busboy's 'finish' event is emitted
|
|
||||||
process.nextTick(cb);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_read(n) {
|
|
||||||
const cb = this._readcb;
|
|
||||||
if (cb) {
|
|
||||||
this._readcb = null;
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ignoreData = {
|
|
||||||
push: (chunk, pos) => {},
|
|
||||||
destroy: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
function callAndUnsetCb(self, err) {
|
|
||||||
const cb = self._writecb;
|
|
||||||
self._writecb = null;
|
|
||||||
if (err)
|
|
||||||
self.destroy(err);
|
|
||||||
else if (cb)
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
function nullDecoder(val, hint) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Multipart extends Writable {
|
|
||||||
constructor(cfg) {
|
|
||||||
const streamOpts = {
|
|
||||||
autoDestroy: true,
|
|
||||||
emitClose: true,
|
|
||||||
highWaterMark: (typeof cfg.highWaterMark === 'number'
|
|
||||||
? cfg.highWaterMark
|
|
||||||
: undefined),
|
|
||||||
};
|
|
||||||
super(streamOpts);
|
|
||||||
|
|
||||||
if (!cfg.conType.params || typeof cfg.conType.params.boundary !== 'string')
|
|
||||||
throw new Error('Multipart: Boundary not found');
|
|
||||||
|
|
||||||
const boundary = cfg.conType.params.boundary;
|
|
||||||
const paramDecoder = (typeof cfg.defParamCharset === 'string'
|
|
||||||
&& cfg.defParamCharset
|
|
||||||
? getDecoder(cfg.defParamCharset)
|
|
||||||
: nullDecoder);
|
|
||||||
const defCharset = (cfg.defCharset || 'utf8');
|
|
||||||
const preservePath = cfg.preservePath;
|
|
||||||
const fileOpts = {
|
|
||||||
autoDestroy: true,
|
|
||||||
emitClose: true,
|
|
||||||
highWaterMark: (typeof cfg.fileHwm === 'number'
|
|
||||||
? cfg.fileHwm
|
|
||||||
: undefined),
|
|
||||||
};
|
|
||||||
|
|
||||||
const limits = cfg.limits;
|
|
||||||
const fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
|
|
||||||
? limits.fieldSize
|
|
||||||
: 1 * 1024 * 1024);
|
|
||||||
const fileSizeLimit = (limits && typeof limits.fileSize === 'number'
|
|
||||||
? limits.fileSize
|
|
||||||
: Infinity);
|
|
||||||
const filesLimit = (limits && typeof limits.files === 'number'
|
|
||||||
? limits.files
|
|
||||||
: Infinity);
|
|
||||||
const fieldsLimit = (limits && typeof limits.fields === 'number'
|
|
||||||
? limits.fields
|
|
||||||
: Infinity);
|
|
||||||
const partsLimit = (limits && typeof limits.parts === 'number'
|
|
||||||
? limits.parts
|
|
||||||
: Infinity);
|
|
||||||
|
|
||||||
let parts = -1; // Account for initial boundary
|
|
||||||
let fields = 0;
|
|
||||||
let files = 0;
|
|
||||||
let skipPart = false;
|
|
||||||
|
|
||||||
this._fileEndsLeft = 0;
|
|
||||||
this._fileStream = undefined;
|
|
||||||
this._complete = false;
|
|
||||||
let fileSize = 0;
|
|
||||||
|
|
||||||
let field;
|
|
||||||
let fieldSize = 0;
|
|
||||||
let partCharset;
|
|
||||||
let partEncoding;
|
|
||||||
let partType;
|
|
||||||
let partName;
|
|
||||||
let partTruncated = false;
|
|
||||||
|
|
||||||
let hitFilesLimit = false;
|
|
||||||
let hitFieldsLimit = false;
|
|
||||||
|
|
||||||
this._hparser = null;
|
|
||||||
const hparser = new HeaderParser((header) => {
|
|
||||||
this._hparser = null;
|
|
||||||
skipPart = false;
|
|
||||||
|
|
||||||
partType = 'text/plain';
|
|
||||||
partCharset = defCharset;
|
|
||||||
partEncoding = '7bit';
|
|
||||||
partName = undefined;
|
|
||||||
partTruncated = false;
|
|
||||||
|
|
||||||
let filename;
|
|
||||||
if (!header['content-disposition']) {
|
|
||||||
skipPart = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const disp = parseDisposition(header['content-disposition'][0],
|
|
||||||
paramDecoder);
|
|
||||||
if (!disp || disp.type !== 'form-data') {
|
|
||||||
skipPart = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disp.params) {
|
|
||||||
if (disp.params.name)
|
|
||||||
partName = disp.params.name;
|
|
||||||
|
|
||||||
if (disp.params['filename*'])
|
|
||||||
filename = disp.params['filename*'];
|
|
||||||
else if (disp.params.filename)
|
|
||||||
filename = disp.params.filename;
|
|
||||||
|
|
||||||
if (filename !== undefined && !preservePath)
|
|
||||||
filename = basename(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header['content-type']) {
|
|
||||||
const conType = parseContentType(header['content-type'][0]);
|
|
||||||
if (conType) {
|
|
||||||
partType = `${conType.type}/${conType.subtype}`;
|
|
||||||
if (conType.params && typeof conType.params.charset === 'string')
|
|
||||||
partCharset = conType.params.charset.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header['content-transfer-encoding'])
|
|
||||||
partEncoding = header['content-transfer-encoding'][0].toLowerCase();
|
|
||||||
|
|
||||||
if (partType === 'application/octet-stream' || filename !== undefined) {
|
|
||||||
// File
|
|
||||||
|
|
||||||
if (files === filesLimit) {
|
|
||||||
if (!hitFilesLimit) {
|
|
||||||
hitFilesLimit = true;
|
|
||||||
this.emit('filesLimit');
|
|
||||||
}
|
|
||||||
skipPart = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++files;
|
|
||||||
|
|
||||||
if (this.listenerCount('file') === 0) {
|
|
||||||
skipPart = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSize = 0;
|
|
||||||
this._fileStream = new FileStream(fileOpts, this);
|
|
||||||
++this._fileEndsLeft;
|
|
||||||
this.emit(
|
|
||||||
'file',
|
|
||||||
partName,
|
|
||||||
this._fileStream,
|
|
||||||
{ filename,
|
|
||||||
encoding: partEncoding,
|
|
||||||
mimeType: partType }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Non-file
|
|
||||||
|
|
||||||
if (fields === fieldsLimit) {
|
|
||||||
if (!hitFieldsLimit) {
|
|
||||||
hitFieldsLimit = true;
|
|
||||||
this.emit('fieldsLimit');
|
|
||||||
}
|
|
||||||
skipPart = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++fields;
|
|
||||||
|
|
||||||
if (this.listenerCount('field') === 0) {
|
|
||||||
skipPart = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
field = [];
|
|
||||||
fieldSize = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let matchPostBoundary = 0;
|
|
||||||
const ssCb = (isMatch, data, start, end, isDataSafe) => {
|
|
||||||
retrydata:
|
|
||||||
while (data) {
|
|
||||||
if (this._hparser !== null) {
|
|
||||||
const ret = this._hparser.push(data, start, end);
|
|
||||||
if (ret === -1) {
|
|
||||||
this._hparser = null;
|
|
||||||
hparser.reset();
|
|
||||||
this.emit('error', new Error('Malformed part header'));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
start = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start === end)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (matchPostBoundary !== 0) {
|
|
||||||
if (matchPostBoundary === 1) {
|
|
||||||
switch (data[start]) {
|
|
||||||
case 45: // '-'
|
|
||||||
// Try matching '--' after boundary
|
|
||||||
matchPostBoundary = 2;
|
|
||||||
++start;
|
|
||||||
break;
|
|
||||||
case 13: // '\r'
|
|
||||||
// Try matching CR LF before header
|
|
||||||
matchPostBoundary = 3;
|
|
||||||
++start;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
matchPostBoundary = 0;
|
|
||||||
}
|
|
||||||
if (start === end)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchPostBoundary === 2) {
|
|
||||||
matchPostBoundary = 0;
|
|
||||||
if (data[start] === 45/* '-' */) {
|
|
||||||
// End of multipart data
|
|
||||||
this._complete = true;
|
|
||||||
this._bparser = ignoreData;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// We saw something other than '-', so put the dash we consumed
|
|
||||||
// "back"
|
|
||||||
const writecb = this._writecb;
|
|
||||||
this._writecb = noop;
|
|
||||||
ssCb(false, BUF_DASH, 0, 1, false);
|
|
||||||
this._writecb = writecb;
|
|
||||||
} else if (matchPostBoundary === 3) {
|
|
||||||
matchPostBoundary = 0;
|
|
||||||
if (data[start] === 10/* '\n' */) {
|
|
||||||
++start;
|
|
||||||
if (parts >= partsLimit)
|
|
||||||
break;
|
|
||||||
// Prepare the header parser
|
|
||||||
this._hparser = hparser;
|
|
||||||
if (start === end)
|
|
||||||
break;
|
|
||||||
// Process the remaining data as a header
|
|
||||||
continue retrydata;
|
|
||||||
} else {
|
|
||||||
// We saw something other than LF, so put the CR we consumed
|
|
||||||
// "back"
|
|
||||||
const writecb = this._writecb;
|
|
||||||
this._writecb = noop;
|
|
||||||
ssCb(false, BUF_CR, 0, 1, false);
|
|
||||||
this._writecb = writecb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!skipPart) {
|
|
||||||
if (this._fileStream) {
|
|
||||||
let chunk;
|
|
||||||
const actualLen = Math.min(end - start, fileSizeLimit - fileSize);
|
|
||||||
if (!isDataSafe) {
|
|
||||||
chunk = Buffer.allocUnsafe(actualLen);
|
|
||||||
data.copy(chunk, 0, start, start + actualLen);
|
|
||||||
} else {
|
|
||||||
chunk = data.slice(start, start + actualLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSize += chunk.length;
|
|
||||||
if (fileSize === fileSizeLimit) {
|
|
||||||
if (chunk.length > 0)
|
|
||||||
this._fileStream.push(chunk);
|
|
||||||
this._fileStream.emit('limit');
|
|
||||||
this._fileStream.truncated = true;
|
|
||||||
skipPart = true;
|
|
||||||
} else if (!this._fileStream.push(chunk)) {
|
|
||||||
if (this._writecb)
|
|
||||||
this._fileStream._readcb = this._writecb;
|
|
||||||
this._writecb = null;
|
|
||||||
}
|
|
||||||
} else if (field !== undefined) {
|
|
||||||
let chunk;
|
|
||||||
const actualLen = Math.min(
|
|
||||||
end - start,
|
|
||||||
fieldSizeLimit - fieldSize
|
|
||||||
);
|
|
||||||
if (!isDataSafe) {
|
|
||||||
chunk = Buffer.allocUnsafe(actualLen);
|
|
||||||
data.copy(chunk, 0, start, start + actualLen);
|
|
||||||
} else {
|
|
||||||
chunk = data.slice(start, start + actualLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldSize += actualLen;
|
|
||||||
field.push(chunk);
|
|
||||||
if (fieldSize === fieldSizeLimit) {
|
|
||||||
skipPart = true;
|
|
||||||
partTruncated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMatch) {
|
|
||||||
matchPostBoundary = 1;
|
|
||||||
|
|
||||||
if (this._fileStream) {
|
|
||||||
// End the active file stream if the previous part was a file
|
|
||||||
this._fileStream.push(null);
|
|
||||||
this._fileStream = null;
|
|
||||||
} else if (field !== undefined) {
|
|
||||||
let data;
|
|
||||||
switch (field.length) {
|
|
||||||
case 0:
|
|
||||||
data = '';
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
data = convertToUTF8(field[0], partCharset, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data = convertToUTF8(
|
|
||||||
Buffer.concat(field, fieldSize),
|
|
||||||
partCharset,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
field = undefined;
|
|
||||||
fieldSize = 0;
|
|
||||||
this.emit(
|
|
||||||
'field',
|
|
||||||
partName,
|
|
||||||
data,
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: partTruncated,
|
|
||||||
encoding: partEncoding,
|
|
||||||
mimeType: partType }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++parts === partsLimit)
|
|
||||||
this.emit('partsLimit');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this._bparser = new StreamSearch(`\r\n--${boundary}`, ssCb);
|
|
||||||
|
|
||||||
this._writecb = null;
|
|
||||||
this._finalcb = null;
|
|
||||||
|
|
||||||
// Just in case there is no preamble
|
|
||||||
this.write(BUF_CRLF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static detect(conType) {
|
|
||||||
return (conType.type === 'multipart' && conType.subtype === 'form-data');
|
|
||||||
}
|
|
||||||
|
|
||||||
_write(chunk, enc, cb) {
|
|
||||||
this._writecb = cb;
|
|
||||||
this._bparser.push(chunk, 0);
|
|
||||||
if (this._writecb)
|
|
||||||
callAndUnsetCb(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_destroy(err, cb) {
|
|
||||||
this._hparser = null;
|
|
||||||
this._bparser = ignoreData;
|
|
||||||
if (!err)
|
|
||||||
err = checkEndState(this);
|
|
||||||
const fileStream = this._fileStream;
|
|
||||||
if (fileStream) {
|
|
||||||
this._fileStream = null;
|
|
||||||
fileStream.destroy(err);
|
|
||||||
}
|
|
||||||
cb(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
_final(cb) {
|
|
||||||
this._bparser.destroy();
|
|
||||||
if (!this._complete)
|
|
||||||
return cb(new Error('Unexpected end of form'));
|
|
||||||
if (this._fileEndsLeft)
|
|
||||||
this._finalcb = finalcb.bind(null, this, cb);
|
|
||||||
else
|
|
||||||
finalcb(this, cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function finalcb(self, cb, err) {
|
|
||||||
if (err)
|
|
||||||
return cb(err);
|
|
||||||
err = checkEndState(self);
|
|
||||||
cb(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkEndState(self) {
|
|
||||||
if (self._hparser)
|
|
||||||
return new Error('Malformed part header');
|
|
||||||
const fileStream = self._fileStream;
|
|
||||||
if (fileStream) {
|
|
||||||
self._fileStream = null;
|
|
||||||
fileStream.destroy(new Error('Unexpected end of file'));
|
|
||||||
}
|
|
||||||
if (!self._complete)
|
|
||||||
return new Error('Unexpected end of form');
|
|
||||||
}
|
|
||||||
|
|
||||||
const TOKEN = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
const FIELD_VCHAR = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
];
|
|
||||||
|
|
||||||
module.exports = Multipart;
|
|
@ -1,350 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { Writable } = require('stream');
|
|
||||||
|
|
||||||
const { getDecoder } = require('../utils.js');
|
|
||||||
|
|
||||||
class URLEncoded extends Writable {
|
|
||||||
constructor(cfg) {
|
|
||||||
const streamOpts = {
|
|
||||||
autoDestroy: true,
|
|
||||||
emitClose: true,
|
|
||||||
highWaterMark: (typeof cfg.highWaterMark === 'number'
|
|
||||||
? cfg.highWaterMark
|
|
||||||
: undefined),
|
|
||||||
};
|
|
||||||
super(streamOpts);
|
|
||||||
|
|
||||||
let charset = (cfg.defCharset || 'utf8');
|
|
||||||
if (cfg.conType.params && typeof cfg.conType.params.charset === 'string')
|
|
||||||
charset = cfg.conType.params.charset;
|
|
||||||
|
|
||||||
this.charset = charset;
|
|
||||||
|
|
||||||
const limits = cfg.limits;
|
|
||||||
this.fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
|
|
||||||
? limits.fieldSize
|
|
||||||
: 1 * 1024 * 1024);
|
|
||||||
this.fieldsLimit = (limits && typeof limits.fields === 'number'
|
|
||||||
? limits.fields
|
|
||||||
: Infinity);
|
|
||||||
this.fieldNameSizeLimit = (
|
|
||||||
limits && typeof limits.fieldNameSize === 'number'
|
|
||||||
? limits.fieldNameSize
|
|
||||||
: 100
|
|
||||||
);
|
|
||||||
|
|
||||||
this._inKey = true;
|
|
||||||
this._keyTrunc = false;
|
|
||||||
this._valTrunc = false;
|
|
||||||
this._bytesKey = 0;
|
|
||||||
this._bytesVal = 0;
|
|
||||||
this._fields = 0;
|
|
||||||
this._key = '';
|
|
||||||
this._val = '';
|
|
||||||
this._byte = -2;
|
|
||||||
this._lastPos = 0;
|
|
||||||
this._encode = 0;
|
|
||||||
this._decoder = getDecoder(charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static detect(conType) {
|
|
||||||
return (conType.type === 'application'
|
|
||||||
&& conType.subtype === 'x-www-form-urlencoded');
|
|
||||||
}
|
|
||||||
|
|
||||||
_write(chunk, enc, cb) {
|
|
||||||
if (this._fields >= this.fieldsLimit)
|
|
||||||
return cb();
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
const len = chunk.length;
|
|
||||||
this._lastPos = 0;
|
|
||||||
|
|
||||||
// Check if we last ended mid-percent-encoded byte
|
|
||||||
if (this._byte !== -2) {
|
|
||||||
i = readPctEnc(this, chunk, i, len);
|
|
||||||
if (i === -1)
|
|
||||||
return cb(new Error('Malformed urlencoded form'));
|
|
||||||
if (i >= len)
|
|
||||||
return cb();
|
|
||||||
if (this._inKey)
|
|
||||||
++this._bytesKey;
|
|
||||||
else
|
|
||||||
++this._bytesVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
main:
|
|
||||||
while (i < len) {
|
|
||||||
if (this._inKey) {
|
|
||||||
// Parsing key
|
|
||||||
|
|
||||||
i = skipKeyBytes(this, chunk, i, len);
|
|
||||||
|
|
||||||
while (i < len) {
|
|
||||||
switch (chunk[i]) {
|
|
||||||
case 61: // '='
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._lastPos = ++i;
|
|
||||||
this._key = this._decoder(this._key, this._encode);
|
|
||||||
this._encode = 0;
|
|
||||||
this._inKey = false;
|
|
||||||
continue main;
|
|
||||||
case 38: // '&'
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._lastPos = ++i;
|
|
||||||
this._key = this._decoder(this._key, this._encode);
|
|
||||||
this._encode = 0;
|
|
||||||
if (this._bytesKey > 0) {
|
|
||||||
this.emit(
|
|
||||||
'field',
|
|
||||||
this._key,
|
|
||||||
'',
|
|
||||||
{ nameTruncated: this._keyTrunc,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: this.charset,
|
|
||||||
mimeType: 'text/plain' }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this._key = '';
|
|
||||||
this._val = '';
|
|
||||||
this._keyTrunc = false;
|
|
||||||
this._valTrunc = false;
|
|
||||||
this._bytesKey = 0;
|
|
||||||
this._bytesVal = 0;
|
|
||||||
if (++this._fields >= this.fieldsLimit) {
|
|
||||||
this.emit('fieldsLimit');
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
case 43: // '+'
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._key += ' ';
|
|
||||||
this._lastPos = i + 1;
|
|
||||||
break;
|
|
||||||
case 37: // '%'
|
|
||||||
if (this._encode === 0)
|
|
||||||
this._encode = 1;
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._lastPos = i + 1;
|
|
||||||
this._byte = -1;
|
|
||||||
i = readPctEnc(this, chunk, i + 1, len);
|
|
||||||
if (i === -1)
|
|
||||||
return cb(new Error('Malformed urlencoded form'));
|
|
||||||
if (i >= len)
|
|
||||||
return cb();
|
|
||||||
++this._bytesKey;
|
|
||||||
i = skipKeyBytes(this, chunk, i, len);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
++this._bytesKey;
|
|
||||||
i = skipKeyBytes(this, chunk, i, len);
|
|
||||||
}
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
} else {
|
|
||||||
// Parsing value
|
|
||||||
|
|
||||||
i = skipValBytes(this, chunk, i, len);
|
|
||||||
|
|
||||||
while (i < len) {
|
|
||||||
switch (chunk[i]) {
|
|
||||||
case 38: // '&'
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._lastPos = ++i;
|
|
||||||
this._inKey = true;
|
|
||||||
this._val = this._decoder(this._val, this._encode);
|
|
||||||
this._encode = 0;
|
|
||||||
if (this._bytesKey > 0 || this._bytesVal > 0) {
|
|
||||||
this.emit(
|
|
||||||
'field',
|
|
||||||
this._key,
|
|
||||||
this._val,
|
|
||||||
{ nameTruncated: this._keyTrunc,
|
|
||||||
valueTruncated: this._valTrunc,
|
|
||||||
encoding: this.charset,
|
|
||||||
mimeType: 'text/plain' }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this._key = '';
|
|
||||||
this._val = '';
|
|
||||||
this._keyTrunc = false;
|
|
||||||
this._valTrunc = false;
|
|
||||||
this._bytesKey = 0;
|
|
||||||
this._bytesVal = 0;
|
|
||||||
if (++this._fields >= this.fieldsLimit) {
|
|
||||||
this.emit('fieldsLimit');
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
continue main;
|
|
||||||
case 43: // '+'
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._val += ' ';
|
|
||||||
this._lastPos = i + 1;
|
|
||||||
break;
|
|
||||||
case 37: // '%'
|
|
||||||
if (this._encode === 0)
|
|
||||||
this._encode = 1;
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
this._lastPos = i + 1;
|
|
||||||
this._byte = -1;
|
|
||||||
i = readPctEnc(this, chunk, i + 1, len);
|
|
||||||
if (i === -1)
|
|
||||||
return cb(new Error('Malformed urlencoded form'));
|
|
||||||
if (i >= len)
|
|
||||||
return cb();
|
|
||||||
++this._bytesVal;
|
|
||||||
i = skipValBytes(this, chunk, i, len);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
++this._bytesVal;
|
|
||||||
i = skipValBytes(this, chunk, i, len);
|
|
||||||
}
|
|
||||||
if (this._lastPos < i)
|
|
||||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
_final(cb) {
|
|
||||||
if (this._byte !== -2)
|
|
||||||
return cb(new Error('Malformed urlencoded form'));
|
|
||||||
if (!this._inKey || this._bytesKey > 0 || this._bytesVal > 0) {
|
|
||||||
if (this._inKey)
|
|
||||||
this._key = this._decoder(this._key, this._encode);
|
|
||||||
else
|
|
||||||
this._val = this._decoder(this._val, this._encode);
|
|
||||||
this.emit(
|
|
||||||
'field',
|
|
||||||
this._key,
|
|
||||||
this._val,
|
|
||||||
{ nameTruncated: this._keyTrunc,
|
|
||||||
valueTruncated: this._valTrunc,
|
|
||||||
encoding: this.charset,
|
|
||||||
mimeType: 'text/plain' }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readPctEnc(self, chunk, pos, len) {
|
|
||||||
if (pos >= len)
|
|
||||||
return len;
|
|
||||||
|
|
||||||
if (self._byte === -1) {
|
|
||||||
// We saw a '%' but no hex characters yet
|
|
||||||
const hexUpper = HEX_VALUES[chunk[pos++]];
|
|
||||||
if (hexUpper === -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (hexUpper >= 8)
|
|
||||||
self._encode = 2; // Indicate high bits detected
|
|
||||||
|
|
||||||
if (pos < len) {
|
|
||||||
// Both hex characters are in this chunk
|
|
||||||
const hexLower = HEX_VALUES[chunk[pos++]];
|
|
||||||
if (hexLower === -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (self._inKey)
|
|
||||||
self._key += String.fromCharCode((hexUpper << 4) + hexLower);
|
|
||||||
else
|
|
||||||
self._val += String.fromCharCode((hexUpper << 4) + hexLower);
|
|
||||||
|
|
||||||
self._byte = -2;
|
|
||||||
self._lastPos = pos;
|
|
||||||
} else {
|
|
||||||
// Only one hex character was available in this chunk
|
|
||||||
self._byte = hexUpper;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We saw only one hex character so far
|
|
||||||
const hexLower = HEX_VALUES[chunk[pos++]];
|
|
||||||
if (hexLower === -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (self._inKey)
|
|
||||||
self._key += String.fromCharCode((self._byte << 4) + hexLower);
|
|
||||||
else
|
|
||||||
self._val += String.fromCharCode((self._byte << 4) + hexLower);
|
|
||||||
|
|
||||||
self._byte = -2;
|
|
||||||
self._lastPos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
function skipKeyBytes(self, chunk, pos, len) {
|
|
||||||
// Skip bytes if we've truncated
|
|
||||||
if (self._bytesKey > self.fieldNameSizeLimit) {
|
|
||||||
if (!self._keyTrunc) {
|
|
||||||
if (self._lastPos < pos)
|
|
||||||
self._key += chunk.latin1Slice(self._lastPos, pos - 1);
|
|
||||||
}
|
|
||||||
self._keyTrunc = true;
|
|
||||||
for (; pos < len; ++pos) {
|
|
||||||
const code = chunk[pos];
|
|
||||||
if (code === 61/* '=' */ || code === 38/* '&' */)
|
|
||||||
break;
|
|
||||||
++self._bytesKey;
|
|
||||||
}
|
|
||||||
self._lastPos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
function skipValBytes(self, chunk, pos, len) {
|
|
||||||
// Skip bytes if we've truncated
|
|
||||||
if (self._bytesVal > self.fieldSizeLimit) {
|
|
||||||
if (!self._valTrunc) {
|
|
||||||
if (self._lastPos < pos)
|
|
||||||
self._val += chunk.latin1Slice(self._lastPos, pos - 1);
|
|
||||||
}
|
|
||||||
self._valTrunc = true;
|
|
||||||
for (; pos < len; ++pos) {
|
|
||||||
if (chunk[pos] === 38/* '&' */)
|
|
||||||
break;
|
|
||||||
++self._bytesVal;
|
|
||||||
}
|
|
||||||
self._lastPos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable no-multi-spaces */
|
|
||||||
const HEX_VALUES = [
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
];
|
|
||||||
/* eslint-enable no-multi-spaces */
|
|
||||||
|
|
||||||
module.exports = URLEncoded;
|
|
@ -1,596 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
function parseContentType(str) {
|
|
||||||
if (str.length === 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const params = Object.create(null);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
// Parse type
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
if (code !== 47/* '/' */ || i === 0)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for type without subtype
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const type = str.slice(0, i).toLowerCase();
|
|
||||||
|
|
||||||
// Parse subtype
|
|
||||||
const subtypeStart = ++i;
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
// Make sure we have a subtype
|
|
||||||
if (i === subtypeStart)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (parseContentTypeParams(str, i, params) === undefined)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure we have a subtype
|
|
||||||
if (i === subtypeStart)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const subtype = str.slice(subtypeStart, i).toLowerCase();
|
|
||||||
|
|
||||||
return { type, subtype, params };
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseContentTypeParams(str, i, params) {
|
|
||||||
while (i < str.length) {
|
|
||||||
// Consume whitespace
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ended on whitespace
|
|
||||||
if (i === str.length)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Check for malformed parameter
|
|
||||||
if (str.charCodeAt(i++) !== 59/* ';' */)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Consume whitespace
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ended on whitespace (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let name;
|
|
||||||
const nameStart = i;
|
|
||||||
// Parse parameter name
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
if (code !== 61/* '=' */)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
name = str.slice(nameStart, i);
|
|
||||||
++i; // Skip over '='
|
|
||||||
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let value = '';
|
|
||||||
let valueStart;
|
|
||||||
if (str.charCodeAt(i) === 34/* '"' */) {
|
|
||||||
valueStart = ++i;
|
|
||||||
let escaping = false;
|
|
||||||
// Parse quoted value
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code === 92/* '\\' */) {
|
|
||||||
if (escaping) {
|
|
||||||
valueStart = i;
|
|
||||||
escaping = false;
|
|
||||||
} else {
|
|
||||||
value += str.slice(valueStart, i);
|
|
||||||
escaping = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (code === 34/* '"' */) {
|
|
||||||
if (escaping) {
|
|
||||||
valueStart = i;
|
|
||||||
escaping = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
value += str.slice(valueStart, i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (escaping) {
|
|
||||||
valueStart = i - 1;
|
|
||||||
escaping = false;
|
|
||||||
}
|
|
||||||
// Invalid unescaped quoted character (malformed)
|
|
||||||
if (QDTEXT[code] !== 1)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No end quote (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
++i; // Skip over double quote
|
|
||||||
} else {
|
|
||||||
valueStart = i;
|
|
||||||
// Parse unquoted value
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === valueStart)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = str.slice(valueStart, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
name = name.toLowerCase();
|
|
||||||
if (params[name] === undefined)
|
|
||||||
params[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDisposition(str, defDecoder) {
|
|
||||||
if (str.length === 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const params = Object.create(null);
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
if (parseDispositionParams(str, i, params, defDecoder) === undefined)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const type = str.slice(0, i).toLowerCase();
|
|
||||||
|
|
||||||
return { type, params };
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDispositionParams(str, i, params, defDecoder) {
|
|
||||||
while (i < str.length) {
|
|
||||||
// Consume whitespace
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ended on whitespace
|
|
||||||
if (i === str.length)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Check for malformed parameter
|
|
||||||
if (str.charCodeAt(i++) !== 59/* ';' */)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Consume whitespace
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ended on whitespace (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let name;
|
|
||||||
const nameStart = i;
|
|
||||||
// Parse parameter name
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
if (code === 61/* '=' */)
|
|
||||||
break;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let value = '';
|
|
||||||
let valueStart;
|
|
||||||
let charset;
|
|
||||||
//~ let lang;
|
|
||||||
name = str.slice(nameStart, i);
|
|
||||||
if (name.charCodeAt(name.length - 1) === 42/* '*' */) {
|
|
||||||
// Extended value
|
|
||||||
|
|
||||||
const charsetStart = ++i;
|
|
||||||
// Parse charset name
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (CHARSET[code] !== 1) {
|
|
||||||
if (code !== 39/* '\'' */)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Incomplete charset (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
charset = str.slice(charsetStart, i);
|
|
||||||
++i; // Skip over the '\''
|
|
||||||
|
|
||||||
//~ const langStart = ++i;
|
|
||||||
// Parse language name
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code === 39/* '\'' */)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Incomplete language (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//~ lang = str.slice(langStart, i);
|
|
||||||
++i; // Skip over the '\''
|
|
||||||
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
valueStart = i;
|
|
||||||
|
|
||||||
let encode = 0;
|
|
||||||
// Parse value
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (EXTENDED_VALUE[code] !== 1) {
|
|
||||||
if (code === 37/* '%' */) {
|
|
||||||
let hexUpper;
|
|
||||||
let hexLower;
|
|
||||||
if (i + 2 < str.length
|
|
||||||
&& (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1
|
|
||||||
&& (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) {
|
|
||||||
const byteVal = (hexUpper << 4) + hexLower;
|
|
||||||
value += str.slice(valueStart, i);
|
|
||||||
value += String.fromCharCode(byteVal);
|
|
||||||
i += 2;
|
|
||||||
valueStart = i + 1;
|
|
||||||
if (byteVal >= 128)
|
|
||||||
encode = 2;
|
|
||||||
else if (encode === 0)
|
|
||||||
encode = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// '%' disallowed in non-percent encoded contexts (malformed)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value += str.slice(valueStart, i);
|
|
||||||
value = convertToUTF8(value, charset, encode);
|
|
||||||
if (value === undefined)
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// Non-extended value
|
|
||||||
|
|
||||||
++i; // Skip over '='
|
|
||||||
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (str.charCodeAt(i) === 34/* '"' */) {
|
|
||||||
valueStart = ++i;
|
|
||||||
let escaping = false;
|
|
||||||
// Parse quoted value
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (code === 92/* '\\' */) {
|
|
||||||
if (escaping) {
|
|
||||||
valueStart = i;
|
|
||||||
escaping = false;
|
|
||||||
} else {
|
|
||||||
value += str.slice(valueStart, i);
|
|
||||||
escaping = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (code === 34/* '"' */) {
|
|
||||||
if (escaping) {
|
|
||||||
valueStart = i;
|
|
||||||
escaping = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
value += str.slice(valueStart, i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (escaping) {
|
|
||||||
valueStart = i - 1;
|
|
||||||
escaping = false;
|
|
||||||
}
|
|
||||||
// Invalid unescaped quoted character (malformed)
|
|
||||||
if (QDTEXT[code] !== 1)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No end quote (malformed)
|
|
||||||
if (i === str.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
++i; // Skip over double quote
|
|
||||||
} else {
|
|
||||||
valueStart = i;
|
|
||||||
// Parse unquoted value
|
|
||||||
for (; i < str.length; ++i) {
|
|
||||||
const code = str.charCodeAt(i);
|
|
||||||
if (TOKEN[code] !== 1) {
|
|
||||||
// No value (malformed)
|
|
||||||
if (i === valueStart)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = str.slice(valueStart, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
value = defDecoder(value, 2);
|
|
||||||
if (value === undefined)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = name.toLowerCase();
|
|
||||||
if (params[name] === undefined)
|
|
||||||
params[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDecoder(charset) {
|
|
||||||
let lc;
|
|
||||||
while (true) {
|
|
||||||
switch (charset) {
|
|
||||||
case 'utf-8':
|
|
||||||
case 'utf8':
|
|
||||||
return decoders.utf8;
|
|
||||||
case 'latin1':
|
|
||||||
case 'ascii': // TODO: Make these a separate, strict decoder?
|
|
||||||
case 'us-ascii':
|
|
||||||
case 'iso-8859-1':
|
|
||||||
case 'iso8859-1':
|
|
||||||
case 'iso88591':
|
|
||||||
case 'iso_8859-1':
|
|
||||||
case 'windows-1252':
|
|
||||||
case 'iso_8859-1:1987':
|
|
||||||
case 'cp1252':
|
|
||||||
case 'x-cp1252':
|
|
||||||
return decoders.latin1;
|
|
||||||
case 'utf16le':
|
|
||||||
case 'utf-16le':
|
|
||||||
case 'ucs2':
|
|
||||||
case 'ucs-2':
|
|
||||||
return decoders.utf16le;
|
|
||||||
case 'base64':
|
|
||||||
return decoders.base64;
|
|
||||||
default:
|
|
||||||
if (lc === undefined) {
|
|
||||||
lc = true;
|
|
||||||
charset = charset.toLowerCase();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return decoders.other.bind(charset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const decoders = {
|
|
||||||
utf8: (data, hint) => {
|
|
||||||
if (data.length === 0)
|
|
||||||
return '';
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
// If `data` never had any percent-encoded bytes or never had any that
|
|
||||||
// were outside of the ASCII range, then we can safely just return the
|
|
||||||
// input since UTF-8 is ASCII compatible
|
|
||||||
if (hint < 2)
|
|
||||||
return data;
|
|
||||||
|
|
||||||
data = Buffer.from(data, 'latin1');
|
|
||||||
}
|
|
||||||
return data.utf8Slice(0, data.length);
|
|
||||||
},
|
|
||||||
|
|
||||||
latin1: (data, hint) => {
|
|
||||||
if (data.length === 0)
|
|
||||||
return '';
|
|
||||||
if (typeof data === 'string')
|
|
||||||
return data;
|
|
||||||
return data.latin1Slice(0, data.length);
|
|
||||||
},
|
|
||||||
|
|
||||||
utf16le: (data, hint) => {
|
|
||||||
if (data.length === 0)
|
|
||||||
return '';
|
|
||||||
if (typeof data === 'string')
|
|
||||||
data = Buffer.from(data, 'latin1');
|
|
||||||
return data.ucs2Slice(0, data.length);
|
|
||||||
},
|
|
||||||
|
|
||||||
base64: (data, hint) => {
|
|
||||||
if (data.length === 0)
|
|
||||||
return '';
|
|
||||||
if (typeof data === 'string')
|
|
||||||
data = Buffer.from(data, 'latin1');
|
|
||||||
return data.base64Slice(0, data.length);
|
|
||||||
},
|
|
||||||
|
|
||||||
other: (data, hint) => {
|
|
||||||
if (data.length === 0)
|
|
||||||
return '';
|
|
||||||
if (typeof data === 'string')
|
|
||||||
data = Buffer.from(data, 'latin1');
|
|
||||||
try {
|
|
||||||
const decoder = new TextDecoder(this);
|
|
||||||
return decoder.decode(data);
|
|
||||||
} catch {}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function convertToUTF8(data, charset, hint) {
|
|
||||||
const decode = getDecoder(charset);
|
|
||||||
if (decode)
|
|
||||||
return decode(data, hint);
|
|
||||||
}
|
|
||||||
|
|
||||||
function basename(path) {
|
|
||||||
if (typeof path !== 'string')
|
|
||||||
return '';
|
|
||||||
for (let i = path.length - 1; i >= 0; --i) {
|
|
||||||
switch (path.charCodeAt(i)) {
|
|
||||||
case 0x2F: // '/'
|
|
||||||
case 0x5C: // '\'
|
|
||||||
path = path.slice(i + 1);
|
|
||||||
return (path === '..' || path === '.' ? '' : path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (path === '..' || path === '.' ? '' : path);
|
|
||||||
}
|
|
||||||
|
|
||||||
const TOKEN = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
const QDTEXT = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
];
|
|
||||||
|
|
||||||
const CHARSET = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
const EXTENDED_VALUE = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
/* eslint-disable no-multi-spaces */
|
|
||||||
const HEX_VALUES = [
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
||||||
];
|
|
||||||
/* eslint-enable no-multi-spaces */
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
basename,
|
|
||||||
convertToUTF8,
|
|
||||||
getDecoder,
|
|
||||||
parseContentType,
|
|
||||||
parseDisposition,
|
|
||||||
};
|
|
@ -1,22 +0,0 @@
|
|||||||
{ "name": "busboy",
|
|
||||||
"version": "1.6.0",
|
|
||||||
"author": "Brian White <mscdex@mscdex.net>",
|
|
||||||
"description": "A streaming parser for HTML form data for node.js",
|
|
||||||
"main": "./lib/index.js",
|
|
||||||
"dependencies": {
|
|
||||||
"streamsearch": "^1.1.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@mscdex/eslint-config": "^1.1.0",
|
|
||||||
"eslint": "^7.32.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "node test/test.js",
|
|
||||||
"lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test bench",
|
|
||||||
"lint:fix": "npm run lint -- --fix"
|
|
||||||
},
|
|
||||||
"engines": { "node": ">=10.16.0" },
|
|
||||||
"keywords": [ "uploads", "forms", "multipart", "form-data" ],
|
|
||||||
"licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/busboy/raw/master/LICENSE" } ],
|
|
||||||
"repository": { "type": "git", "url": "http://github.com/mscdex/busboy.git" }
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const { inspect } = require('util');
|
|
||||||
|
|
||||||
const mustCallChecks = [];
|
|
||||||
|
|
||||||
function noop() {}
|
|
||||||
|
|
||||||
function runCallChecks(exitCode) {
|
|
||||||
if (exitCode !== 0) return;
|
|
||||||
|
|
||||||
const failed = mustCallChecks.filter((context) => {
|
|
||||||
if ('minimum' in context) {
|
|
||||||
context.messageSegment = `at least ${context.minimum}`;
|
|
||||||
return context.actual < context.minimum;
|
|
||||||
}
|
|
||||||
context.messageSegment = `exactly ${context.exact}`;
|
|
||||||
return context.actual !== context.exact;
|
|
||||||
});
|
|
||||||
|
|
||||||
failed.forEach((context) => {
|
|
||||||
console.error('Mismatched %s function calls. Expected %s, actual %d.',
|
|
||||||
context.name,
|
|
||||||
context.messageSegment,
|
|
||||||
context.actual);
|
|
||||||
console.error(context.stack.split('\n').slice(2).join('\n'));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (failed.length)
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mustCall(fn, exact) {
|
|
||||||
return _mustCallInner(fn, exact, 'exact');
|
|
||||||
}
|
|
||||||
|
|
||||||
function mustCallAtLeast(fn, minimum) {
|
|
||||||
return _mustCallInner(fn, minimum, 'minimum');
|
|
||||||
}
|
|
||||||
|
|
||||||
function _mustCallInner(fn, criteria = 1, field) {
|
|
||||||
if (process._exiting)
|
|
||||||
throw new Error('Cannot use common.mustCall*() in process exit handler');
|
|
||||||
|
|
||||||
if (typeof fn === 'number') {
|
|
||||||
criteria = fn;
|
|
||||||
fn = noop;
|
|
||||||
} else if (fn === undefined) {
|
|
||||||
fn = noop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof criteria !== 'number')
|
|
||||||
throw new TypeError(`Invalid ${field} value: ${criteria}`);
|
|
||||||
|
|
||||||
const context = {
|
|
||||||
[field]: criteria,
|
|
||||||
actual: 0,
|
|
||||||
stack: inspect(new Error()),
|
|
||||||
name: fn.name || '<anonymous>'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the exit listener only once to avoid listener leak warnings
|
|
||||||
if (mustCallChecks.length === 0)
|
|
||||||
process.on('exit', runCallChecks);
|
|
||||||
|
|
||||||
mustCallChecks.push(context);
|
|
||||||
|
|
||||||
function wrapped(...args) {
|
|
||||||
++context.actual;
|
|
||||||
return fn.call(this, ...args);
|
|
||||||
}
|
|
||||||
// TODO: remove origFn?
|
|
||||||
wrapped.origFn = fn;
|
|
||||||
|
|
||||||
return wrapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCallSite(top) {
|
|
||||||
const originalStackFormatter = Error.prepareStackTrace;
|
|
||||||
Error.prepareStackTrace = (err, stack) =>
|
|
||||||
`${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
|
|
||||||
const err = new Error();
|
|
||||||
Error.captureStackTrace(err, top);
|
|
||||||
// With the V8 Error API, the stack is not formatted until it is accessed
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
|
||||||
err.stack;
|
|
||||||
Error.prepareStackTrace = originalStackFormatter;
|
|
||||||
return err.stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mustNotCall(msg) {
|
|
||||||
const callSite = getCallSite(mustNotCall);
|
|
||||||
return function mustNotCall(...args) {
|
|
||||||
args = args.map(inspect).join(', ');
|
|
||||||
const argsInfo = (args.length > 0
|
|
||||||
? `\ncalled with arguments: ${args}`
|
|
||||||
: '');
|
|
||||||
assert.fail(
|
|
||||||
`${msg || 'function should not have been called'} at ${callSite}`
|
|
||||||
+ argsInfo);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mustCall,
|
|
||||||
mustCallAtLeast,
|
|
||||||
mustNotCall,
|
|
||||||
};
|
|
@ -1,94 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const { inspect } = require('util');
|
|
||||||
|
|
||||||
const { mustCall } = require(`${__dirname}/common.js`);
|
|
||||||
|
|
||||||
const busboy = require('..');
|
|
||||||
|
|
||||||
const input = Buffer.from([
|
|
||||||
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
|
|
||||||
'Content-Disposition: form-data; '
|
|
||||||
+ 'name="upload_file_0"; filename="テスト.dat"',
|
|
||||||
'Content-Type: application/octet-stream',
|
|
||||||
'',
|
|
||||||
'A'.repeat(1023),
|
|
||||||
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
|
|
||||||
].join('\r\n'));
|
|
||||||
const boundary = '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k';
|
|
||||||
const expected = [
|
|
||||||
{ type: 'file',
|
|
||||||
name: 'upload_file_0',
|
|
||||||
data: Buffer.from('A'.repeat(1023)),
|
|
||||||
info: {
|
|
||||||
filename: 'テスト.dat',
|
|
||||||
encoding: '7bit',
|
|
||||||
mimeType: 'application/octet-stream',
|
|
||||||
},
|
|
||||||
limited: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const bb = busboy({
|
|
||||||
defParamCharset: 'utf8',
|
|
||||||
headers: {
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
bb.on('field', (name, val, info) => {
|
|
||||||
results.push({ type: 'field', name, val, info });
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('file', (name, stream, info) => {
|
|
||||||
const data = [];
|
|
||||||
let nb = 0;
|
|
||||||
const file = {
|
|
||||||
type: 'file',
|
|
||||||
name,
|
|
||||||
data: null,
|
|
||||||
info,
|
|
||||||
limited: false,
|
|
||||||
};
|
|
||||||
results.push(file);
|
|
||||||
stream.on('data', (d) => {
|
|
||||||
data.push(d);
|
|
||||||
nb += d.length;
|
|
||||||
}).on('limit', () => {
|
|
||||||
file.limited = true;
|
|
||||||
}).on('close', () => {
|
|
||||||
file.data = Buffer.concat(data, nb);
|
|
||||||
assert.strictEqual(stream.truncated, file.limited);
|
|
||||||
}).once('error', (err) => {
|
|
||||||
file.err = err.message;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('error', (err) => {
|
|
||||||
results.push({ error: err.message });
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('partsLimit', () => {
|
|
||||||
results.push('partsLimit');
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('filesLimit', () => {
|
|
||||||
results.push('filesLimit');
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('fieldsLimit', () => {
|
|
||||||
results.push('fieldsLimit');
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('close', mustCall(() => {
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
results,
|
|
||||||
expected,
|
|
||||||
'Results mismatch.\n'
|
|
||||||
+ `Parsed: ${inspect(results)}\n`
|
|
||||||
+ `Expected: ${inspect(expected)}`
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
|
|
||||||
bb.end(input);
|
|
@ -1,102 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const { randomFillSync } = require('crypto');
|
|
||||||
const { inspect } = require('util');
|
|
||||||
|
|
||||||
const busboy = require('..');
|
|
||||||
|
|
||||||
const { mustCall } = require('./common.js');
|
|
||||||
|
|
||||||
const BOUNDARY = 'u2KxIV5yF1y+xUspOQCCZopaVgeV6Jxihv35XQJmuTx8X3sh';
|
|
||||||
|
|
||||||
function formDataSection(key, value) {
|
|
||||||
return Buffer.from(
|
|
||||||
`\r\n--${BOUNDARY}`
|
|
||||||
+ `\r\nContent-Disposition: form-data; name="${key}"`
|
|
||||||
+ `\r\n\r\n${value}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formDataFile(key, filename, contentType) {
|
|
||||||
const buf = Buffer.allocUnsafe(100000);
|
|
||||||
return Buffer.concat([
|
|
||||||
Buffer.from(`\r\n--${BOUNDARY}\r\n`),
|
|
||||||
Buffer.from(`Content-Disposition: form-data; name="${key}"`
|
|
||||||
+ `; filename="${filename}"\r\n`),
|
|
||||||
Buffer.from(`Content-Type: ${contentType}\r\n\r\n`),
|
|
||||||
randomFillSync(buf)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const reqChunks = [
|
|
||||||
Buffer.concat([
|
|
||||||
formDataFile('file', 'file.bin', 'application/octet-stream'),
|
|
||||||
formDataSection('foo', 'foo value'),
|
|
||||||
]),
|
|
||||||
formDataSection('bar', 'bar value'),
|
|
||||||
Buffer.from(`\r\n--${BOUNDARY}--\r\n`)
|
|
||||||
];
|
|
||||||
const bb = busboy({
|
|
||||||
headers: {
|
|
||||||
'content-type': `multipart/form-data; boundary=${BOUNDARY}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const expected = [
|
|
||||||
{ type: 'file',
|
|
||||||
name: 'file',
|
|
||||||
info: {
|
|
||||||
filename: 'file.bin',
|
|
||||||
encoding: '7bit',
|
|
||||||
mimeType: 'application/octet-stream',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ type: 'field',
|
|
||||||
name: 'foo',
|
|
||||||
val: 'foo value',
|
|
||||||
info: {
|
|
||||||
nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: '7bit',
|
|
||||||
mimeType: 'text/plain',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ type: 'field',
|
|
||||||
name: 'bar',
|
|
||||||
val: 'bar value',
|
|
||||||
info: {
|
|
||||||
nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: '7bit',
|
|
||||||
mimeType: 'text/plain',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
bb.on('field', (name, val, info) => {
|
|
||||||
results.push({ type: 'field', name, val, info });
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('file', (name, stream, info) => {
|
|
||||||
results.push({ type: 'file', name, info });
|
|
||||||
// Simulate a pipe where the destination is pausing (perhaps due to waiting
|
|
||||||
// for file system write to finish)
|
|
||||||
setTimeout(() => {
|
|
||||||
stream.resume();
|
|
||||||
}, 10);
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('close', mustCall(() => {
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
results,
|
|
||||||
expected,
|
|
||||||
'Results mismatch.\n'
|
|
||||||
+ `Parsed: ${inspect(results)}\n`
|
|
||||||
+ `Expected: ${inspect(expected)}`
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
|
|
||||||
for (const chunk of reqChunks)
|
|
||||||
bb.write(chunk);
|
|
||||||
bb.end();
|
|
File diff suppressed because it is too large
Load Diff
@ -1,488 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const { transcode } = require('buffer');
|
|
||||||
const { inspect } = require('util');
|
|
||||||
|
|
||||||
const busboy = require('..');
|
|
||||||
|
|
||||||
const active = new Map();
|
|
||||||
|
|
||||||
const tests = [
|
|
||||||
{ source: ['foo'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Unassigned value'
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Assigned value'
|
|
||||||
},
|
|
||||||
{ source: ['foo&bar=baz'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['bar',
|
|
||||||
'baz',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Unassigned and assigned value'
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['baz',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Assigned and unassigned value'
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['baz',
|
|
||||||
'bla',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Two assigned values'
|
|
||||||
},
|
|
||||||
{ source: ['foo&bar'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['bar',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Two unassigned values'
|
|
||||||
},
|
|
||||||
{ source: ['foo&bar&'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['bar',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Two unassigned values and ampersand'
|
|
||||||
},
|
|
||||||
{ source: ['foo+1=bar+baz%2Bquux'],
|
|
||||||
expected: [
|
|
||||||
['foo 1',
|
|
||||||
'bar baz+quux',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Assigned key and value with (plus) space'
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar%20baz%21'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar baz!',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Assigned value with encoded bytes'
|
|
||||||
},
|
|
||||||
{ source: ['foo%20bar=baz%20bla%21'],
|
|
||||||
expected: [
|
|
||||||
['foo bar',
|
|
||||||
'baz bla!',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Assigned value with encoded bytes #2'
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar%20baz%21&num=1000'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar baz!',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['num',
|
|
||||||
'1000',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Two assigned values, one with encoded bytes'
|
|
||||||
},
|
|
||||||
{ source: [
|
|
||||||
Array.from(transcode(Buffer.from('foo'), 'utf8', 'utf16le')).map(
|
|
||||||
(n) => `%${n.toString(16).padStart(2, '0')}`
|
|
||||||
).join(''),
|
|
||||||
'=',
|
|
||||||
Array.from(transcode(Buffer.from('😀!'), 'utf8', 'utf16le')).map(
|
|
||||||
(n) => `%${n.toString(16).padStart(2, '0')}`
|
|
||||||
).join(''),
|
|
||||||
],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'😀!',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'UTF-16LE',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
charset: 'UTF-16LE',
|
|
||||||
what: 'Encoded value with multi-byte charset'
|
|
||||||
},
|
|
||||||
{ source: [
|
|
||||||
'foo=<',
|
|
||||||
Array.from(transcode(Buffer.from('©:^þ'), 'utf8', 'latin1')).map(
|
|
||||||
(n) => `%${n.toString(16).padStart(2, '0')}`
|
|
||||||
).join(''),
|
|
||||||
],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'<©:^þ',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'ISO-8859-1',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
charset: 'ISO-8859-1',
|
|
||||||
what: 'Encoded value with single-byte, ASCII-compatible, non-UTF8 charset'
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [],
|
|
||||||
what: 'Limits: zero fields',
|
|
||||||
limits: { fields: 0 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: one field',
|
|
||||||
limits: { fields: 1 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'bar',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['baz',
|
|
||||||
'bla',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: field part lengths match limits',
|
|
||||||
limits: { fieldNameSize: 3, fieldSize: 3 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['fo',
|
|
||||||
'bar',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['ba',
|
|
||||||
'bla',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: truncated field name',
|
|
||||||
limits: { fieldNameSize: 2 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['foo',
|
|
||||||
'ba',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['baz',
|
|
||||||
'bl',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: truncated field value',
|
|
||||||
limits: { fieldSize: 2 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['fo',
|
|
||||||
'ba',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['ba',
|
|
||||||
'bl',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: truncated field name and value',
|
|
||||||
limits: { fieldNameSize: 2, fieldSize: 2 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['fo',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['ba',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: truncated field name and zero value limit',
|
|
||||||
limits: { fieldNameSize: 2, fieldSize: 0 }
|
|
||||||
},
|
|
||||||
{ source: ['foo=bar&baz=bla'],
|
|
||||||
expected: [
|
|
||||||
['',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
['',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: true,
|
|
||||||
valueTruncated: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Limits: truncated zero field name and zero value limit',
|
|
||||||
limits: { fieldNameSize: 0, fieldSize: 0 }
|
|
||||||
},
|
|
||||||
{ source: ['&'],
|
|
||||||
expected: [],
|
|
||||||
what: 'Ampersand'
|
|
||||||
},
|
|
||||||
{ source: ['&&&&&'],
|
|
||||||
expected: [],
|
|
||||||
what: 'Many ampersands'
|
|
||||||
},
|
|
||||||
{ source: ['='],
|
|
||||||
expected: [
|
|
||||||
['',
|
|
||||||
'',
|
|
||||||
{ nameTruncated: false,
|
|
||||||
valueTruncated: false,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
mimeType: 'text/plain' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
what: 'Assigned value, empty name and value'
|
|
||||||
},
|
|
||||||
{ source: [''],
|
|
||||||
expected: [],
|
|
||||||
what: 'Nothing'
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const test of tests) {
|
|
||||||
active.set(test, 1);
|
|
||||||
|
|
||||||
const { what } = test;
|
|
||||||
const charset = test.charset || 'utf-8';
|
|
||||||
const bb = busboy({
|
|
||||||
limits: test.limits,
|
|
||||||
headers: {
|
|
||||||
'content-type': `application/x-www-form-urlencoded; charset=${charset}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
bb.on('field', (key, val, info) => {
|
|
||||||
results.push([key, val, info]);
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('file', () => {
|
|
||||||
throw new Error(`[${what}] Unexpected file`);
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('close', () => {
|
|
||||||
active.delete(test);
|
|
||||||
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
results,
|
|
||||||
test.expected,
|
|
||||||
`[${what}] Results mismatch.\n`
|
|
||||||
+ `Parsed: ${inspect(results)}\n`
|
|
||||||
+ `Expected: ${inspect(test.expected)}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const src of test.source) {
|
|
||||||
const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
|
|
||||||
bb.write(buf);
|
|
||||||
}
|
|
||||||
bb.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Byte-by-byte versions
|
|
||||||
for (let test of tests) {
|
|
||||||
test = { ...test };
|
|
||||||
test.what += ' (byte-by-byte)';
|
|
||||||
active.set(test, 1);
|
|
||||||
|
|
||||||
const { what } = test;
|
|
||||||
const charset = test.charset || 'utf-8';
|
|
||||||
const bb = busboy({
|
|
||||||
limits: test.limits,
|
|
||||||
headers: {
|
|
||||||
'content-type': `application/x-www-form-urlencoded; charset="${charset}"`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
bb.on('field', (key, val, info) => {
|
|
||||||
results.push([key, val, info]);
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('file', () => {
|
|
||||||
throw new Error(`[${what}] Unexpected file`);
|
|
||||||
});
|
|
||||||
|
|
||||||
bb.on('close', () => {
|
|
||||||
active.delete(test);
|
|
||||||
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
results,
|
|
||||||
test.expected,
|
|
||||||
`[${what}] Results mismatch.\n`
|
|
||||||
+ `Parsed: ${inspect(results)}\n`
|
|
||||||
+ `Expected: ${inspect(test.expected)}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const src of test.source) {
|
|
||||||
const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
|
|
||||||
for (let i = 0; i < buf.length; ++i)
|
|
||||||
bb.write(buf.slice(i, i + 1));
|
|
||||||
}
|
|
||||||
bb.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let exception = false;
|
|
||||||
process.once('uncaughtException', (ex) => {
|
|
||||||
exception = true;
|
|
||||||
throw ex;
|
|
||||||
});
|
|
||||||
process.on('exit', () => {
|
|
||||||
if (exception || active.size === 0)
|
|
||||||
return;
|
|
||||||
process.exitCode = 1;
|
|
||||||
console.error('==========================');
|
|
||||||
console.error(`${active.size} test(s) did not finish:`);
|
|
||||||
console.error('==========================');
|
|
||||||
console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { spawnSync } = require('child_process');
|
|
||||||
const { readdirSync } = require('fs');
|
|
||||||
const { join } = require('path');
|
|
||||||
|
|
||||||
const files = readdirSync(__dirname).sort();
|
|
||||||
for (const filename of files) {
|
|
||||||
if (filename.startsWith('test-')) {
|
|
||||||
const path = join(__dirname, filename);
|
|
||||||
console.log(`> Running ${filename} ...`);
|
|
||||||
const result = spawnSync(`${process.argv0} ${path}`, {
|
|
||||||
shell: true,
|
|
||||||
stdio: 'inherit',
|
|
||||||
windowsHide: true
|
|
||||||
});
|
|
||||||
if (result.status !== 0)
|
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2013 Max Ogden
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge,
|
|
||||||
to any person obtaining a copy of this software and
|
|
||||||
associated documentation files (the "Software"), to
|
|
||||||
deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify,
|
|
||||||
merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom
|
|
||||||
the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
|
||||||
shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
||||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,144 +0,0 @@
|
|||||||
var Writable = require('readable-stream').Writable
|
|
||||||
var inherits = require('inherits')
|
|
||||||
var bufferFrom = require('buffer-from')
|
|
||||||
|
|
||||||
if (typeof Uint8Array === 'undefined') {
|
|
||||||
var U8 = require('typedarray').Uint8Array
|
|
||||||
} else {
|
|
||||||
var U8 = Uint8Array
|
|
||||||
}
|
|
||||||
|
|
||||||
function ConcatStream(opts, cb) {
|
|
||||||
if (!(this instanceof ConcatStream)) return new ConcatStream(opts, cb)
|
|
||||||
|
|
||||||
if (typeof opts === 'function') {
|
|
||||||
cb = opts
|
|
||||||
opts = {}
|
|
||||||
}
|
|
||||||
if (!opts) opts = {}
|
|
||||||
|
|
||||||
var encoding = opts.encoding
|
|
||||||
var shouldInferEncoding = false
|
|
||||||
|
|
||||||
if (!encoding) {
|
|
||||||
shouldInferEncoding = true
|
|
||||||
} else {
|
|
||||||
encoding = String(encoding).toLowerCase()
|
|
||||||
if (encoding === 'u8' || encoding === 'uint8') {
|
|
||||||
encoding = 'uint8array'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Writable.call(this, { objectMode: true })
|
|
||||||
|
|
||||||
this.encoding = encoding
|
|
||||||
this.shouldInferEncoding = shouldInferEncoding
|
|
||||||
|
|
||||||
if (cb) this.on('finish', function () { cb(this.getBody()) })
|
|
||||||
this.body = []
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ConcatStream
|
|
||||||
inherits(ConcatStream, Writable)
|
|
||||||
|
|
||||||
ConcatStream.prototype._write = function(chunk, enc, next) {
|
|
||||||
this.body.push(chunk)
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
|
|
||||||
ConcatStream.prototype.inferEncoding = function (buff) {
|
|
||||||
var firstBuffer = buff === undefined ? this.body[0] : buff;
|
|
||||||
if (Buffer.isBuffer(firstBuffer)) return 'buffer'
|
|
||||||
if (typeof Uint8Array !== 'undefined' && firstBuffer instanceof Uint8Array) return 'uint8array'
|
|
||||||
if (Array.isArray(firstBuffer)) return 'array'
|
|
||||||
if (typeof firstBuffer === 'string') return 'string'
|
|
||||||
if (Object.prototype.toString.call(firstBuffer) === "[object Object]") return 'object'
|
|
||||||
return 'buffer'
|
|
||||||
}
|
|
||||||
|
|
||||||
ConcatStream.prototype.getBody = function () {
|
|
||||||
if (!this.encoding && this.body.length === 0) return []
|
|
||||||
if (this.shouldInferEncoding) this.encoding = this.inferEncoding()
|
|
||||||
if (this.encoding === 'array') return arrayConcat(this.body)
|
|
||||||
if (this.encoding === 'string') return stringConcat(this.body)
|
|
||||||
if (this.encoding === 'buffer') return bufferConcat(this.body)
|
|
||||||
if (this.encoding === 'uint8array') return u8Concat(this.body)
|
|
||||||
return this.body
|
|
||||||
}
|
|
||||||
|
|
||||||
var isArray = Array.isArray || function (arr) {
|
|
||||||
return Object.prototype.toString.call(arr) == '[object Array]'
|
|
||||||
}
|
|
||||||
|
|
||||||
function isArrayish (arr) {
|
|
||||||
return /Array\]$/.test(Object.prototype.toString.call(arr))
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBufferish (p) {
|
|
||||||
return typeof p === 'string' || isArrayish(p) || (p && typeof p.subarray === 'function')
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringConcat (parts) {
|
|
||||||
var strings = []
|
|
||||||
var needsToString = false
|
|
||||||
for (var i = 0; i < parts.length; i++) {
|
|
||||||
var p = parts[i]
|
|
||||||
if (typeof p === 'string') {
|
|
||||||
strings.push(p)
|
|
||||||
} else if (Buffer.isBuffer(p)) {
|
|
||||||
strings.push(p)
|
|
||||||
} else if (isBufferish(p)) {
|
|
||||||
strings.push(bufferFrom(p))
|
|
||||||
} else {
|
|
||||||
strings.push(bufferFrom(String(p)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Buffer.isBuffer(parts[0])) {
|
|
||||||
strings = Buffer.concat(strings)
|
|
||||||
strings = strings.toString('utf8')
|
|
||||||
} else {
|
|
||||||
strings = strings.join('')
|
|
||||||
}
|
|
||||||
return strings
|
|
||||||
}
|
|
||||||
|
|
||||||
function bufferConcat (parts) {
|
|
||||||
var bufs = []
|
|
||||||
for (var i = 0; i < parts.length; i++) {
|
|
||||||
var p = parts[i]
|
|
||||||
if (Buffer.isBuffer(p)) {
|
|
||||||
bufs.push(p)
|
|
||||||
} else if (isBufferish(p)) {
|
|
||||||
bufs.push(bufferFrom(p))
|
|
||||||
} else {
|
|
||||||
bufs.push(bufferFrom(String(p)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Buffer.concat(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
function arrayConcat (parts) {
|
|
||||||
var res = []
|
|
||||||
for (var i = 0; i < parts.length; i++) {
|
|
||||||
res.push.apply(res, parts[i])
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
function u8Concat (parts) {
|
|
||||||
var len = 0
|
|
||||||
for (var i = 0; i < parts.length; i++) {
|
|
||||||
if (typeof parts[i] === 'string') {
|
|
||||||
parts[i] = bufferFrom(parts[i])
|
|
||||||
}
|
|
||||||
len += parts[i].length
|
|
||||||
}
|
|
||||||
var u8 = new U8(len)
|
|
||||||
for (var i = 0, offset = 0; i < parts.length; i++) {
|
|
||||||
var part = parts[i]
|
|
||||||
for (var j = 0; j < part.length; j++) {
|
|
||||||
u8[offset++] = part[j]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return u8
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "concat-stream",
|
|
||||||
"version": "1.6.2",
|
|
||||||
"description": "writable stream that concatenates strings or binary data and calls a callback with the result",
|
|
||||||
"tags": [
|
|
||||||
"stream",
|
|
||||||
"simple",
|
|
||||||
"util",
|
|
||||||
"utility"
|
|
||||||
],
|
|
||||||
"author": "Max Ogden <max@maxogden.com>",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "http://github.com/maxogden/concat-stream.git"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "http://github.com/maxogden/concat-stream/issues"
|
|
||||||
},
|
|
||||||
"engines": [
|
|
||||||
"node >= 0.8"
|
|
||||||
],
|
|
||||||
"main": "index.js",
|
|
||||||
"files": [
|
|
||||||
"index.js"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"test": "tape test/*.js test/server/*.js"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"buffer-from": "^1.0.0",
|
|
||||||
"inherits": "^2.0.3",
|
|
||||||
"readable-stream": "^2.2.2",
|
|
||||||
"typedarray": "^0.0.6"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"tape": "^4.6.3"
|
|
||||||
},
|
|
||||||
"testling": {
|
|
||||||
"files": "test/*.js",
|
|
||||||
"browsers": [
|
|
||||||
"ie/8..latest",
|
|
||||||
"firefox/17..latest",
|
|
||||||
"firefox/nightly",
|
|
||||||
"chrome/22..latest",
|
|
||||||
"chrome/canary",
|
|
||||||
"opera/12..latest",
|
|
||||||
"opera/next",
|
|
||||||
"safari/5.1..latest",
|
|
||||||
"ipad/6.0..latest",
|
|
||||||
"iphone/6.0..latest",
|
|
||||||
"android-browser/4.2..latest"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
# concat-stream
|
|
||||||
|
|
||||||
Writable stream that concatenates all the data from a stream and calls a callback with the result. Use this when you want to collect all the data from a stream into a single buffer.
|
|
||||||
|
|
||||||
[](https://travis-ci.org/maxogden/concat-stream)
|
|
||||||
|
|
||||||
[](https://nodei.co/npm/concat-stream/)
|
|
||||||
|
|
||||||
### description
|
|
||||||
|
|
||||||
Streams emit many buffers. If you want to collect all of the buffers, and when the stream ends concatenate all of the buffers together and receive a single buffer then this is the module for you.
|
|
||||||
|
|
||||||
Only use this if you know you can fit all of the output of your stream into a single Buffer (e.g. in RAM).
|
|
||||||
|
|
||||||
There are also `objectMode` streams that emit things other than Buffers, and you can concatenate these too. See below for details.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
`concat-stream` is part of the [mississippi stream utility collection](https://github.com/maxogden/mississippi) which includes more useful stream modules similar to this one.
|
|
||||||
|
|
||||||
### examples
|
|
||||||
|
|
||||||
#### Buffers
|
|
||||||
|
|
||||||
```js
|
|
||||||
var fs = require('fs')
|
|
||||||
var concat = require('concat-stream')
|
|
||||||
|
|
||||||
var readStream = fs.createReadStream('cat.png')
|
|
||||||
var concatStream = concat(gotPicture)
|
|
||||||
|
|
||||||
readStream.on('error', handleError)
|
|
||||||
readStream.pipe(concatStream)
|
|
||||||
|
|
||||||
function gotPicture(imageBuffer) {
|
|
||||||
// imageBuffer is all of `cat.png` as a node.js Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleError(err) {
|
|
||||||
// handle your error appropriately here, e.g.:
|
|
||||||
console.error(err) // print the error to STDERR
|
|
||||||
process.exit(1) // exit program with non-zero exit code
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Arrays
|
|
||||||
|
|
||||||
```js
|
|
||||||
var write = concat(function(data) {})
|
|
||||||
write.write([1,2,3])
|
|
||||||
write.write([4,5,6])
|
|
||||||
write.end()
|
|
||||||
// data will be [1,2,3,4,5,6] in the above callback
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Uint8Arrays
|
|
||||||
|
|
||||||
```js
|
|
||||||
var write = concat(function(data) {})
|
|
||||||
var a = new Uint8Array(3)
|
|
||||||
a[0] = 97; a[1] = 98; a[2] = 99
|
|
||||||
write.write(a)
|
|
||||||
write.write('!')
|
|
||||||
write.end(Buffer.from('!!1'))
|
|
||||||
```
|
|
||||||
|
|
||||||
See `test/` for more examples
|
|
||||||
|
|
||||||
# methods
|
|
||||||
|
|
||||||
```js
|
|
||||||
var concat = require('concat-stream')
|
|
||||||
```
|
|
||||||
|
|
||||||
## var writable = concat(opts={}, cb)
|
|
||||||
|
|
||||||
Return a `writable` stream that will fire `cb(data)` with all of the data that
|
|
||||||
was written to the stream. Data can be written to `writable` as strings,
|
|
||||||
Buffers, arrays of byte integers, and Uint8Arrays.
|
|
||||||
|
|
||||||
By default `concat-stream` will give you back the same data type as the type of the first buffer written to the stream. Use `opts.encoding` to set what format `data` should be returned as, e.g. if you if you don't want to rely on the built-in type checking or for some other reason.
|
|
||||||
|
|
||||||
* `string` - get a string
|
|
||||||
* `buffer` - get back a Buffer
|
|
||||||
* `array` - get an array of byte integers
|
|
||||||
* `uint8array`, `u8`, `uint8` - get back a Uint8Array
|
|
||||||
* `object`, get back an array of Objects
|
|
||||||
|
|
||||||
If you don't specify an encoding, and the types can't be inferred (e.g. you write things that aren't in the list above), it will try to convert concat them into a `Buffer`.
|
|
||||||
|
|
||||||
If nothing is written to `writable` then `data` will be an empty array `[]`.
|
|
||||||
|
|
||||||
# error handling
|
|
||||||
|
|
||||||
`concat-stream` does not handle errors for you, so you must handle errors on whatever streams you pipe into `concat-stream`. This is a general rule when programming with node.js streams: always handle errors on each and every stream. Since `concat-stream` is not itself a stream it does not emit errors.
|
|
||||||
|
|
||||||
We recommend using [`end-of-stream`](https://npmjs.org/end-of-stream) or [`pump`](https://npmjs.org/pump) for writing error tolerant stream code.
|
|
||||||
|
|
||||||
# license
|
|
||||||
|
|
||||||
MIT LICENSE
|
|
@ -1,19 +0,0 @@
|
|||||||
Copyright Node.js contributors. All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to
|
|
||||||
deal in the Software without restriction, including without limitation the
|
|
||||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
IN THE SOFTWARE.
|
|
@ -1,3 +0,0 @@
|
|||||||
# core-util-is
|
|
||||||
|
|
||||||
The `util.is*` functions introduced in Node v0.12.
|
|
@ -1,107 +0,0 @@
|
|||||||
// Copyright Joyent, Inc. and other Node contributors.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the
|
|
||||||
// "Software"), to deal in the Software without restriction, including
|
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
||||||
// persons to whom the Software is furnished to do so, subject to the
|
|
||||||
// following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included
|
|
||||||
// in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
||||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
||||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: These type checking functions intentionally don't use `instanceof`
|
|
||||||
// because it is fragile and can be easily faked with `Object.create()`.
|
|
||||||
|
|
||||||
function isArray(arg) {
|
|
||||||
if (Array.isArray) {
|
|
||||||
return Array.isArray(arg);
|
|
||||||
}
|
|
||||||
return objectToString(arg) === '[object Array]';
|
|
||||||
}
|
|
||||||
exports.isArray = isArray;
|
|
||||||
|
|
||||||
function isBoolean(arg) {
|
|
||||||
return typeof arg === 'boolean';
|
|
||||||
}
|
|
||||||
exports.isBoolean = isBoolean;
|
|
||||||
|
|
||||||
function isNull(arg) {
|
|
||||||
return arg === null;
|
|
||||||
}
|
|
||||||
exports.isNull = isNull;
|
|
||||||
|
|
||||||
function isNullOrUndefined(arg) {
|
|
||||||
return arg == null;
|
|
||||||
}
|
|
||||||
exports.isNullOrUndefined = isNullOrUndefined;
|
|
||||||
|
|
||||||
function isNumber(arg) {
|
|
||||||
return typeof arg === 'number';
|
|
||||||
}
|
|
||||||
exports.isNumber = isNumber;
|
|
||||||
|
|
||||||
function isString(arg) {
|
|
||||||
return typeof arg === 'string';
|
|
||||||
}
|
|
||||||
exports.isString = isString;
|
|
||||||
|
|
||||||
function isSymbol(arg) {
|
|
||||||
return typeof arg === 'symbol';
|
|
||||||
}
|
|
||||||
exports.isSymbol = isSymbol;
|
|
||||||
|
|
||||||
function isUndefined(arg) {
|
|
||||||
return arg === void 0;
|
|
||||||
}
|
|
||||||
exports.isUndefined = isUndefined;
|
|
||||||
|
|
||||||
function isRegExp(re) {
|
|
||||||
return objectToString(re) === '[object RegExp]';
|
|
||||||
}
|
|
||||||
exports.isRegExp = isRegExp;
|
|
||||||
|
|
||||||
function isObject(arg) {
|
|
||||||
return typeof arg === 'object' && arg !== null;
|
|
||||||
}
|
|
||||||
exports.isObject = isObject;
|
|
||||||
|
|
||||||
function isDate(d) {
|
|
||||||
return objectToString(d) === '[object Date]';
|
|
||||||
}
|
|
||||||
exports.isDate = isDate;
|
|
||||||
|
|
||||||
function isError(e) {
|
|
||||||
return (objectToString(e) === '[object Error]' || e instanceof Error);
|
|
||||||
}
|
|
||||||
exports.isError = isError;
|
|
||||||
|
|
||||||
function isFunction(arg) {
|
|
||||||
return typeof arg === 'function';
|
|
||||||
}
|
|
||||||
exports.isFunction = isFunction;
|
|
||||||
|
|
||||||
function isPrimitive(arg) {
|
|
||||||
return arg === null ||
|
|
||||||
typeof arg === 'boolean' ||
|
|
||||||
typeof arg === 'number' ||
|
|
||||||
typeof arg === 'string' ||
|
|
||||||
typeof arg === 'symbol' || // ES6 symbol
|
|
||||||
typeof arg === 'undefined';
|
|
||||||
}
|
|
||||||
exports.isPrimitive = isPrimitive;
|
|
||||||
|
|
||||||
exports.isBuffer = require('buffer').Buffer.isBuffer;
|
|
||||||
|
|
||||||
function objectToString(o) {
|
|
||||||
return Object.prototype.toString.call(o);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "core-util-is",
|
|
||||||
"version": "1.0.3",
|
|
||||||
"description": "The `util.is*` functions introduced in Node v0.12.",
|
|
||||||
"main": "lib/util.js",
|
|
||||||
"files": [
|
|
||||||
"lib"
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/isaacs/core-util-is"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"util",
|
|
||||||
"isBuffer",
|
|
||||||
"isArray",
|
|
||||||
"isNumber",
|
|
||||||
"isString",
|
|
||||||
"isRegExp",
|
|
||||||
"isThis",
|
|
||||||
"isThat",
|
|
||||||
"polyfill"
|
|
||||||
],
|
|
||||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
|
||||||
"license": "MIT",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/isaacs/core-util-is/issues"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "tap test.js",
|
|
||||||
"preversion": "npm test",
|
|
||||||
"postversion": "npm publish",
|
|
||||||
"prepublishOnly": "git push origin --follow-tags"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"tap": "^15.0.9"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
The ISC License
|
|
||||||
|
|
||||||
Copyright (c) Isaac Z. Schlueter
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
||||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
||||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
||||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
|||||||
Browser-friendly inheritance fully compatible with standard node.js
|
|
||||||
[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
|
|
||||||
|
|
||||||
This package exports standard `inherits` from node.js `util` module in
|
|
||||||
node environment, but also provides alternative browser-friendly
|
|
||||||
implementation through [browser
|
|
||||||
field](https://gist.github.com/shtylman/4339901). Alternative
|
|
||||||
implementation is a literal copy of standard one located in standalone
|
|
||||||
module to avoid requiring of `util`. It also has a shim for old
|
|
||||||
browsers with no `Object.create` support.
|
|
||||||
|
|
||||||
While keeping you sure you are using standard `inherits`
|
|
||||||
implementation in node.js environment, it allows bundlers such as
|
|
||||||
[browserify](https://github.com/substack/node-browserify) to not
|
|
||||||
include full `util` package to your client code if all you need is
|
|
||||||
just `inherits` function. It worth, because browser shim for `util`
|
|
||||||
package is large and `inherits` is often the single function you need
|
|
||||||
from it.
|
|
||||||
|
|
||||||
It's recommended to use this package instead of
|
|
||||||
`require('util').inherits` for any code that has chances to be used
|
|
||||||
not only in node.js but in browser too.
|
|
||||||
|
|
||||||
## usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
var inherits = require('inherits');
|
|
||||||
// then use exactly as the standard one
|
|
||||||
```
|
|
||||||
|
|
||||||
## note on version ~1.0
|
|
||||||
|
|
||||||
Version ~1.0 had completely different motivation and is not compatible
|
|
||||||
neither with 2.0 nor with standard node.js `inherits`.
|
|
||||||
|
|
||||||
If you are using version ~1.0 and planning to switch to ~2.0, be
|
|
||||||
careful:
|
|
||||||
|
|
||||||
* new version uses `super_` instead of `super` for referencing
|
|
||||||
superclass
|
|
||||||
* new version overwrites current prototype while old one preserves any
|
|
||||||
existing fields on it
|
|
@ -1,9 +0,0 @@
|
|||||||
try {
|
|
||||||
var util = require('util');
|
|
||||||
/* istanbul ignore next */
|
|
||||||
if (typeof util.inherits !== 'function') throw '';
|
|
||||||
module.exports = util.inherits;
|
|
||||||
} catch (e) {
|
|
||||||
/* istanbul ignore next */
|
|
||||||
module.exports = require('./inherits_browser.js');
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
if (typeof Object.create === 'function') {
|
|
||||||
// implementation from standard node.js 'util' module
|
|
||||||
module.exports = function inherits(ctor, superCtor) {
|
|
||||||
if (superCtor) {
|
|
||||||
ctor.super_ = superCtor
|
|
||||||
ctor.prototype = Object.create(superCtor.prototype, {
|
|
||||||
constructor: {
|
|
||||||
value: ctor,
|
|
||||||
enumerable: false,
|
|
||||||
writable: true,
|
|
||||||
configurable: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// old school shim for old browsers
|
|
||||||
module.exports = function inherits(ctor, superCtor) {
|
|
||||||
if (superCtor) {
|
|
||||||
ctor.super_ = superCtor
|
|
||||||
var TempCtor = function () {}
|
|
||||||
TempCtor.prototype = superCtor.prototype
|
|
||||||
ctor.prototype = new TempCtor()
|
|
||||||
ctor.prototype.constructor = ctor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "inherits",
|
|
||||||
"description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
|
|
||||||
"version": "2.0.4",
|
|
||||||
"keywords": [
|
|
||||||
"inheritance",
|
|
||||||
"class",
|
|
||||||
"klass",
|
|
||||||
"oop",
|
|
||||||
"object-oriented",
|
|
||||||
"inherits",
|
|
||||||
"browser",
|
|
||||||
"browserify"
|
|
||||||
],
|
|
||||||
"main": "./inherits.js",
|
|
||||||
"browser": "./inherits_browser.js",
|
|
||||||
"repository": "git://github.com/isaacs/inherits",
|
|
||||||
"license": "ISC",
|
|
||||||
"scripts": {
|
|
||||||
"test": "tap"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"tap": "^14.2.4"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"inherits.js",
|
|
||||||
"inherits_browser.js"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- "0.8"
|
|
||||||
- "0.10"
|
|
@ -1,6 +0,0 @@
|
|||||||
|
|
||||||
test:
|
|
||||||
@node_modules/.bin/tape test.js
|
|
||||||
|
|
||||||
.PHONY: test
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
|
|
||||||
# isarray
|
|
||||||
|
|
||||||
`Array#isArray` for older browsers.
|
|
||||||
|
|
||||||
[](http://travis-ci.org/juliangruber/isarray)
|
|
||||||
[](https://www.npmjs.org/package/isarray)
|
|
||||||
|
|
||||||
[
|
|
||||||
](https://ci.testling.com/juliangruber/isarray)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
var isArray = require('isarray');
|
|
||||||
|
|
||||||
console.log(isArray([])); // => true
|
|
||||||
console.log(isArray({})); // => false
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
With [npm](http://npmjs.org) do
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm install isarray
|
|
||||||
```
|
|
||||||
|
|
||||||
Then bundle for the browser with
|
|
||||||
[browserify](https://github.com/substack/browserify).
|
|
||||||
|
|
||||||
With [component](http://component.io) do
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ component install juliangruber/isarray
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
(MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name" : "isarray",
|
|
||||||
"description" : "Array#isArray for older browsers",
|
|
||||||
"version" : "0.0.1",
|
|
||||||
"repository" : "juliangruber/isarray",
|
|
||||||
"homepage": "https://github.com/juliangruber/isarray",
|
|
||||||
"main" : "index.js",
|
|
||||||
"scripts" : [
|
|
||||||
"index.js"
|
|
||||||
],
|
|
||||||
"dependencies" : {},
|
|
||||||
"keywords": ["browser","isarray","array"],
|
|
||||||
"author": {
|
|
||||||
"name": "Julian Gruber",
|
|
||||||
"email": "mail@juliangruber.com",
|
|
||||||
"url": "http://juliangruber.com"
|
|
||||||
},
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
var toString = {}.toString;
|
|
||||||
|
|
||||||
module.exports = Array.isArray || function (arr) {
|
|
||||||
return toString.call(arr) == '[object Array]';
|
|
||||||
};
|
|
@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "isarray",
|
|
||||||
"description": "Array#isArray for older browsers",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/juliangruber/isarray.git"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/juliangruber/isarray",
|
|
||||||
"main": "index.js",
|
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
|
||||||
"tape": "~2.13.4"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"browser",
|
|
||||||
"isarray",
|
|
||||||
"array"
|
|
||||||
],
|
|
||||||
"author": {
|
|
||||||
"name": "Julian Gruber",
|
|
||||||
"email": "mail@juliangruber.com",
|
|
||||||
"url": "http://juliangruber.com"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"testling": {
|
|
||||||
"files": "test.js",
|
|
||||||
"browsers": [
|
|
||||||
"ie/8..latest",
|
|
||||||
"firefox/17..latest",
|
|
||||||
"firefox/nightly",
|
|
||||||
"chrome/22..latest",
|
|
||||||
"chrome/canary",
|
|
||||||
"opera/12..latest",
|
|
||||||
"opera/next",
|
|
||||||
"safari/5.1..latest",
|
|
||||||
"ipad/6.0..latest",
|
|
||||||
"iphone/6.0..latest",
|
|
||||||
"android-browser/4.2..latest"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "tape test.js"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
var isArray = require('./');
|
|
||||||
var test = require('tape');
|
|
||||||
|
|
||||||
test('is array', function(t){
|
|
||||||
t.ok(isArray([]));
|
|
||||||
t.notOk(isArray({}));
|
|
||||||
t.notOk(isArray(null));
|
|
||||||
t.notOk(isArray(false));
|
|
||||||
|
|
||||||
var obj = {};
|
|
||||||
obj[0] = true;
|
|
||||||
t.notOk(isArray(obj));
|
|
||||||
|
|
||||||
var arr = [];
|
|
||||||
arr.foo = 'bar';
|
|
||||||
t.ok(isArray(arr));
|
|
||||||
|
|
||||||
t.end();
|
|
||||||
});
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
0.3.0 / 2014-09-07
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Support Node.js 0.6
|
|
||||||
* Throw error when parameter format invalid on parse
|
|
||||||
|
|
||||||
0.2.0 / 2014-06-18
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `typer.format()` to format media types
|
|
||||||
|
|
||||||
0.1.0 / 2014-06-17
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Accept `req` as argument to `parse`
|
|
||||||
* Accept `res` as argument to `parse`
|
|
||||||
* Parse media type with extra LWS between type and first parameter
|
|
||||||
|
|
||||||
0.0.0 / 2014-06-13
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Initial implementation
|
|
@ -1,22 +0,0 @@
|
|||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Douglas Christopher Wilson
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
'Software'), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,81 +0,0 @@
|
|||||||
# media-typer
|
|
||||||
|
|
||||||
[![NPM Version][npm-image]][npm-url]
|
|
||||||
[![NPM Downloads][downloads-image]][downloads-url]
|
|
||||||
[![Node.js Version][node-version-image]][node-version-url]
|
|
||||||
[![Build Status][travis-image]][travis-url]
|
|
||||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
||||||
|
|
||||||
Simple RFC 6838 media type parser
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm install media-typer
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```js
|
|
||||||
var typer = require('media-typer')
|
|
||||||
```
|
|
||||||
|
|
||||||
### typer.parse(string)
|
|
||||||
|
|
||||||
```js
|
|
||||||
var obj = typer.parse('image/svg+xml; charset=utf-8')
|
|
||||||
```
|
|
||||||
|
|
||||||
Parse a media type string. This will return an object with the following
|
|
||||||
properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):
|
|
||||||
|
|
||||||
- `type`: The type of the media type (always lower case). Example: `'image'`
|
|
||||||
|
|
||||||
- `subtype`: The subtype of the media type (always lower case). Example: `'svg'`
|
|
||||||
|
|
||||||
- `suffix`: The suffix of the media type (always lower case). Example: `'xml'`
|
|
||||||
|
|
||||||
- `parameters`: An object of the parameters in the media type (name of parameter always lower case). Example: `{charset: 'utf-8'}`
|
|
||||||
|
|
||||||
### typer.parse(req)
|
|
||||||
|
|
||||||
```js
|
|
||||||
var obj = typer.parse(req)
|
|
||||||
```
|
|
||||||
|
|
||||||
Parse the `content-type` header from the given `req`. Short-cut for
|
|
||||||
`typer.parse(req.headers['content-type'])`.
|
|
||||||
|
|
||||||
### typer.parse(res)
|
|
||||||
|
|
||||||
```js
|
|
||||||
var obj = typer.parse(res)
|
|
||||||
```
|
|
||||||
|
|
||||||
Parse the `content-type` header set on the given `res`. Short-cut for
|
|
||||||
`typer.parse(res.getHeader('content-type'))`.
|
|
||||||
|
|
||||||
### typer.format(obj)
|
|
||||||
|
|
||||||
```js
|
|
||||||
var obj = typer.format({type: 'image', subtype: 'svg', suffix: 'xml'})
|
|
||||||
```
|
|
||||||
|
|
||||||
Format an object into a media type string. This will return a string of the
|
|
||||||
mime type for the given object. For the properties of the object, see the
|
|
||||||
documentation for `typer.parse(string)`.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[MIT](LICENSE)
|
|
||||||
|
|
||||||
[npm-image]: https://img.shields.io/npm/v/media-typer.svg?style=flat
|
|
||||||
[npm-url]: https://npmjs.org/package/media-typer
|
|
||||||
[node-version-image]: https://img.shields.io/badge/node.js-%3E%3D_0.6-brightgreen.svg?style=flat
|
|
||||||
[node-version-url]: http://nodejs.org/download/
|
|
||||||
[travis-image]: https://img.shields.io/travis/jshttp/media-typer.svg?style=flat
|
|
||||||
[travis-url]: https://travis-ci.org/jshttp/media-typer
|
|
||||||
[coveralls-image]: https://img.shields.io/coveralls/jshttp/media-typer.svg?style=flat
|
|
||||||
[coveralls-url]: https://coveralls.io/r/jshttp/media-typer
|
|
||||||
[downloads-image]: https://img.shields.io/npm/dm/media-typer.svg?style=flat
|
|
||||||
[downloads-url]: https://npmjs.org/package/media-typer
|
|
@ -1,270 +0,0 @@
|
|||||||
/*!
|
|
||||||
* media-typer
|
|
||||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RegExp to match *( ";" parameter ) in RFC 2616 sec 3.7
|
|
||||||
*
|
|
||||||
* parameter = token "=" ( token | quoted-string )
|
|
||||||
* token = 1*<any CHAR except CTLs or separators>
|
|
||||||
* separators = "(" | ")" | "<" | ">" | "@"
|
|
||||||
* | "," | ";" | ":" | "\" | <">
|
|
||||||
* | "/" | "[" | "]" | "?" | "="
|
|
||||||
* | "{" | "}" | SP | HT
|
|
||||||
* quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
|
|
||||||
* qdtext = <any TEXT except <">>
|
|
||||||
* quoted-pair = "\" CHAR
|
|
||||||
* CHAR = <any US-ASCII character (octets 0 - 127)>
|
|
||||||
* TEXT = <any OCTET except CTLs, but including LWS>
|
|
||||||
* LWS = [CRLF] 1*( SP | HT )
|
|
||||||
* CRLF = CR LF
|
|
||||||
* CR = <US-ASCII CR, carriage return (13)>
|
|
||||||
* LF = <US-ASCII LF, linefeed (10)>
|
|
||||||
* SP = <US-ASCII SP, space (32)>
|
|
||||||
* SHT = <US-ASCII HT, horizontal-tab (9)>
|
|
||||||
* CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
|
|
||||||
* OCTET = <any 8-bit sequence of data>
|
|
||||||
*/
|
|
||||||
var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
|
|
||||||
var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/
|
|
||||||
var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RegExp to match quoted-pair in RFC 2616
|
|
||||||
*
|
|
||||||
* quoted-pair = "\" CHAR
|
|
||||||
* CHAR = <any US-ASCII character (octets 0 - 127)>
|
|
||||||
*/
|
|
||||||
var qescRegExp = /\\([\u0000-\u007f])/g;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RegExp to match chars that must be quoted-pair in RFC 2616
|
|
||||||
*/
|
|
||||||
var quoteRegExp = /([\\"])/g;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RegExp to match type in RFC 6838
|
|
||||||
*
|
|
||||||
* type-name = restricted-name
|
|
||||||
* subtype-name = restricted-name
|
|
||||||
* restricted-name = restricted-name-first *126restricted-name-chars
|
|
||||||
* restricted-name-first = ALPHA / DIGIT
|
|
||||||
* restricted-name-chars = ALPHA / DIGIT / "!" / "#" /
|
|
||||||
* "$" / "&" / "-" / "^" / "_"
|
|
||||||
* restricted-name-chars =/ "." ; Characters before first dot always
|
|
||||||
* ; specify a facet name
|
|
||||||
* restricted-name-chars =/ "+" ; Characters after last plus always
|
|
||||||
* ; specify a structured syntax suffix
|
|
||||||
* ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
|
||||||
* DIGIT = %x30-39 ; 0-9
|
|
||||||
*/
|
|
||||||
var subtypeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/
|
|
||||||
var typeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/
|
|
||||||
var typeRegExp = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module exports.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.format = format
|
|
||||||
exports.parse = parse
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format object to media type.
|
|
||||||
*
|
|
||||||
* @param {object} obj
|
|
||||||
* @return {string}
|
|
||||||
* @api public
|
|
||||||
*/
|
|
||||||
|
|
||||||
function format(obj) {
|
|
||||||
if (!obj || typeof obj !== 'object') {
|
|
||||||
throw new TypeError('argument obj is required')
|
|
||||||
}
|
|
||||||
|
|
||||||
var parameters = obj.parameters
|
|
||||||
var subtype = obj.subtype
|
|
||||||
var suffix = obj.suffix
|
|
||||||
var type = obj.type
|
|
||||||
|
|
||||||
if (!type || !typeNameRegExp.test(type)) {
|
|
||||||
throw new TypeError('invalid type')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subtype || !subtypeNameRegExp.test(subtype)) {
|
|
||||||
throw new TypeError('invalid subtype')
|
|
||||||
}
|
|
||||||
|
|
||||||
// format as type/subtype
|
|
||||||
var string = type + '/' + subtype
|
|
||||||
|
|
||||||
// append +suffix
|
|
||||||
if (suffix) {
|
|
||||||
if (!typeNameRegExp.test(suffix)) {
|
|
||||||
throw new TypeError('invalid suffix')
|
|
||||||
}
|
|
||||||
|
|
||||||
string += '+' + suffix
|
|
||||||
}
|
|
||||||
|
|
||||||
// append parameters
|
|
||||||
if (parameters && typeof parameters === 'object') {
|
|
||||||
var param
|
|
||||||
var params = Object.keys(parameters).sort()
|
|
||||||
|
|
||||||
for (var i = 0; i < params.length; i++) {
|
|
||||||
param = params[i]
|
|
||||||
|
|
||||||
if (!tokenRegExp.test(param)) {
|
|
||||||
throw new TypeError('invalid parameter name')
|
|
||||||
}
|
|
||||||
|
|
||||||
string += '; ' + param + '=' + qstring(parameters[param])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse media type to object.
|
|
||||||
*
|
|
||||||
* @param {string|object} string
|
|
||||||
* @return {Object}
|
|
||||||
* @api public
|
|
||||||
*/
|
|
||||||
|
|
||||||
function parse(string) {
|
|
||||||
if (!string) {
|
|
||||||
throw new TypeError('argument string is required')
|
|
||||||
}
|
|
||||||
|
|
||||||
// support req/res-like objects as argument
|
|
||||||
if (typeof string === 'object') {
|
|
||||||
string = getcontenttype(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof string !== 'string') {
|
|
||||||
throw new TypeError('argument string is required to be a string')
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = string.indexOf(';')
|
|
||||||
var type = index !== -1
|
|
||||||
? string.substr(0, index)
|
|
||||||
: string
|
|
||||||
|
|
||||||
var key
|
|
||||||
var match
|
|
||||||
var obj = splitType(type)
|
|
||||||
var params = {}
|
|
||||||
var value
|
|
||||||
|
|
||||||
paramRegExp.lastIndex = index
|
|
||||||
|
|
||||||
while (match = paramRegExp.exec(string)) {
|
|
||||||
if (match.index !== index) {
|
|
||||||
throw new TypeError('invalid parameter format')
|
|
||||||
}
|
|
||||||
|
|
||||||
index += match[0].length
|
|
||||||
key = match[1].toLowerCase()
|
|
||||||
value = match[2]
|
|
||||||
|
|
||||||
if (value[0] === '"') {
|
|
||||||
// remove quotes and escapes
|
|
||||||
value = value
|
|
||||||
.substr(1, value.length - 2)
|
|
||||||
.replace(qescRegExp, '$1')
|
|
||||||
}
|
|
||||||
|
|
||||||
params[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index !== -1 && index !== string.length) {
|
|
||||||
throw new TypeError('invalid parameter format')
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.parameters = params
|
|
||||||
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get content-type from req/res objects.
|
|
||||||
*
|
|
||||||
* @param {object}
|
|
||||||
* @return {Object}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function getcontenttype(obj) {
|
|
||||||
if (typeof obj.getHeader === 'function') {
|
|
||||||
// res-like
|
|
||||||
return obj.getHeader('content-type')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof obj.headers === 'object') {
|
|
||||||
// req-like
|
|
||||||
return obj.headers && obj.headers['content-type']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quote a string if necessary.
|
|
||||||
*
|
|
||||||
* @param {string} val
|
|
||||||
* @return {string}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function qstring(val) {
|
|
||||||
var str = String(val)
|
|
||||||
|
|
||||||
// no need to quote tokens
|
|
||||||
if (tokenRegExp.test(str)) {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str.length > 0 && !textRegExp.test(str)) {
|
|
||||||
throw new TypeError('invalid parameter value')
|
|
||||||
}
|
|
||||||
|
|
||||||
return '"' + str.replace(quoteRegExp, '\\$1') + '"'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simply "type/subtype+siffx" into parts.
|
|
||||||
*
|
|
||||||
* @param {string} string
|
|
||||||
* @return {Object}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function splitType(string) {
|
|
||||||
var match = typeRegExp.exec(string.toLowerCase())
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
throw new TypeError('invalid media type')
|
|
||||||
}
|
|
||||||
|
|
||||||
var type = match[1]
|
|
||||||
var subtype = match[2]
|
|
||||||
var suffix
|
|
||||||
|
|
||||||
// suffix after last +
|
|
||||||
var index = subtype.lastIndexOf('+')
|
|
||||||
if (index !== -1) {
|
|
||||||
suffix = subtype.substr(index + 1)
|
|
||||||
subtype = subtype.substr(0, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
var obj = {
|
|
||||||
type: type,
|
|
||||||
subtype: subtype,
|
|
||||||
suffix: suffix
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "media-typer",
|
|
||||||
"description": "Simple RFC 6838 media type parser and formatter",
|
|
||||||
"version": "0.3.0",
|
|
||||||
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": "jshttp/media-typer",
|
|
||||||
"devDependencies": {
|
|
||||||
"istanbul": "0.3.2",
|
|
||||||
"mocha": "~1.21.4",
|
|
||||||
"should": "~4.0.4"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"LICENSE",
|
|
||||||
"HISTORY.md",
|
|
||||||
"index.js"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "mocha --reporter spec --check-leaks --bail test/",
|
|
||||||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
|
|
||||||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,507 +0,0 @@
|
|||||||
1.52.0 / 2022-02-21
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extensions from IANA for more `image/*` types
|
|
||||||
* Add extension `.asc` to `application/pgp-keys`
|
|
||||||
* Add extensions to various XML types
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.51.0 / 2021-11-08
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Mark `image/vnd.microsoft.icon` as compressible
|
|
||||||
* Mark `image/vnd.ms-dds` as compressible
|
|
||||||
|
|
||||||
1.50.0 / 2021-09-15
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add deprecated iWorks mime types and extensions
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.49.0 / 2021-07-26
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extension `.trig` to `application/trig`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.48.0 / 2021-05-30
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extension `.mvt` to `application/vnd.mapbox-vector-tile`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Mark `text/yaml` as compressible
|
|
||||||
|
|
||||||
1.47.0 / 2021-04-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Remove ambigious extensions from IANA for `application/*+xml` types
|
|
||||||
* Update primary extension to `.es` for `application/ecmascript`
|
|
||||||
|
|
||||||
1.46.0 / 2021-02-13
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extension `.amr` to `audio/amr`
|
|
||||||
* Add extension `.m4s` to `video/iso.segment`
|
|
||||||
* Add extension `.opus` to `audio/ogg`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.45.0 / 2020-09-22
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/ubjson` with extension `.ubj`
|
|
||||||
* Add `image/avif` with extension `.avif`
|
|
||||||
* Add `image/ktx2` with extension `.ktx2`
|
|
||||||
* Add extension `.dbf` to `application/vnd.dbf`
|
|
||||||
* Add extension `.rar` to `application/vnd.rar`
|
|
||||||
* Add extension `.td` to `application/urc-targetdesc+xml`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Fix extension of `application/vnd.apple.keynote` to be `.key`
|
|
||||||
|
|
||||||
1.44.0 / 2020-04-22
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add charsets from IANA
|
|
||||||
* Add extension `.cjs` to `application/node`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.43.0 / 2020-01-05
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/x-keepass2` with extension `.kdbx`
|
|
||||||
* Add extension `.mxmf` to `audio/mobile-xmf`
|
|
||||||
* Add extensions from IANA for `application/*+xml` types
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.42.0 / 2019-09-25
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `image/vnd.ms-dds` with extension `.dds`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Remove compressible from `multipart/mixed`
|
|
||||||
|
|
||||||
1.41.0 / 2019-08-30
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add `application/toml` with extension `.toml`
|
|
||||||
* Mark `font/ttf` as compressible
|
|
||||||
|
|
||||||
1.40.0 / 2019-04-20
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extensions from IANA for `model/*` types
|
|
||||||
* Add `text/mdx` with extension `.mdx`
|
|
||||||
|
|
||||||
1.39.0 / 2019-04-04
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extensions `.siv` and `.sieve` to `application/sieve`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.38.0 / 2019-02-04
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extension `.nq` to `application/n-quads`
|
|
||||||
* Add extension `.nt` to `application/n-triples`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Mark `text/less` as compressible
|
|
||||||
|
|
||||||
1.37.0 / 2018-10-19
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extensions to HEIC image types
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.36.0 / 2018-08-20
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add Apple file extensions from IANA
|
|
||||||
* Add extensions from IANA for `image/*` types
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.35.0 / 2018-07-15
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extension `.owl` to `application/rdf+xml`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
- Removes extension `.woff` from `application/font-woff`
|
|
||||||
|
|
||||||
1.34.0 / 2018-06-03
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extension `.csl` to `application/vnd.citationstyles.style+xml`
|
|
||||||
* Add extension `.es` to `application/ecmascript`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add `UTF-8` as default charset for `text/turtle`
|
|
||||||
* Mark all XML-derived types as compressible
|
|
||||||
|
|
||||||
1.33.0 / 2018-02-15
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add extensions from IANA for `message/*` types
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Fix some incorrect OOXML types
|
|
||||||
* Remove `application/font-woff2`
|
|
||||||
|
|
||||||
1.32.0 / 2017-11-29
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Update `text/hjson` to registered `application/hjson`
|
|
||||||
* Add `text/shex` with extension `.shex`
|
|
||||||
|
|
||||||
1.31.0 / 2017-10-25
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/raml+yaml` with extension `.raml`
|
|
||||||
* Add `application/wasm` with extension `.wasm`
|
|
||||||
* Add new `font` type from IANA
|
|
||||||
* Add new upstream font extensions
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add extensions for JPEG-2000 images
|
|
||||||
|
|
||||||
1.30.0 / 2017-08-27
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/vnd.ms-outlook`
|
|
||||||
* Add `application/x-arj`
|
|
||||||
* Add extension `.mjs` to `application/javascript`
|
|
||||||
* Add glTF types and extensions
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add `text/x-org`
|
|
||||||
* Add VirtualBox MIME types
|
|
||||||
* Fix `source` records for `video/*` types that are IANA
|
|
||||||
* Update `font/opentype` to registered `font/otf`
|
|
||||||
|
|
||||||
1.29.0 / 2017-07-10
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/fido.trusted-apps+json`
|
|
||||||
* Add extension `.wadl` to `application/vnd.sun.wadl+xml`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add `UTF-8` as default charset for `text/css`
|
|
||||||
|
|
||||||
1.28.0 / 2017-05-14
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add extension `.gz` to `application/gzip`
|
|
||||||
* Update extensions `.md` and `.markdown` to be `text/markdown`
|
|
||||||
|
|
||||||
1.27.0 / 2017-03-16
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add `image/apng` with extension `.apng`
|
|
||||||
|
|
||||||
1.26.0 / 2017-01-14
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add extension `.geojson` to `application/geo+json`
|
|
||||||
|
|
||||||
1.25.0 / 2016-11-11
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.24.0 / 2016-09-18
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `audio/mp3`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.23.0 / 2016-05-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Add extension `.3gpp` to `audio/3gpp`
|
|
||||||
|
|
||||||
1.22.0 / 2016-02-15
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `text/slim`
|
|
||||||
* Add extension `.rng` to `application/xml`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
* Fix extension of `application/dash+xml` to be `.mpd`
|
|
||||||
* Update primary extension to `.m4a` for `audio/mp4`
|
|
||||||
|
|
||||||
1.21.0 / 2016-01-06
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add Google document types
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.20.0 / 2015-11-10
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `text/x-suse-ymp`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.19.0 / 2015-09-17
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/vnd.apple.pkpass`
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.18.0 / 2015-09-03
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add new upstream MIME types
|
|
||||||
|
|
||||||
1.17.0 / 2015-08-13
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/x-msdos-program`
|
|
||||||
* Add `audio/g711-0`
|
|
||||||
* Add `image/vnd.mozilla.apng`
|
|
||||||
* Add extension `.exe` to `application/x-msdos-program`
|
|
||||||
|
|
||||||
1.16.0 / 2015-07-29
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/vnd.uri-map`
|
|
||||||
|
|
||||||
1.15.0 / 2015-07-13
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/x-httpd-php`
|
|
||||||
|
|
||||||
1.14.0 / 2015-06-25
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/scim+json`
|
|
||||||
* Add `application/vnd.3gpp.ussd+xml`
|
|
||||||
* Add `application/vnd.biopax.rdf+xml`
|
|
||||||
* Add `text/x-processing`
|
|
||||||
|
|
||||||
1.13.0 / 2015-06-07
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add nginx as a source
|
|
||||||
* Add `application/x-cocoa`
|
|
||||||
* Add `application/x-java-archive-diff`
|
|
||||||
* Add `application/x-makeself`
|
|
||||||
* Add `application/x-perl`
|
|
||||||
* Add `application/x-pilot`
|
|
||||||
* Add `application/x-redhat-package-manager`
|
|
||||||
* Add `application/x-sea`
|
|
||||||
* Add `audio/x-m4a`
|
|
||||||
* Add `audio/x-realaudio`
|
|
||||||
* Add `image/x-jng`
|
|
||||||
* Add `text/mathml`
|
|
||||||
|
|
||||||
1.12.0 / 2015-06-05
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/bdoc`
|
|
||||||
* Add `application/vnd.hyperdrive+json`
|
|
||||||
* Add `application/x-bdoc`
|
|
||||||
* Add extension `.rtf` to `text/rtf`
|
|
||||||
|
|
||||||
1.11.0 / 2015-05-31
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `audio/wav`
|
|
||||||
* Add `audio/wave`
|
|
||||||
* Add extension `.litcoffee` to `text/coffeescript`
|
|
||||||
* Add extension `.sfd-hdstx` to `application/vnd.hydrostatix.sof-data`
|
|
||||||
* Add extension `.n-gage` to `application/vnd.nokia.n-gage.symbian.install`
|
|
||||||
|
|
||||||
1.10.0 / 2015-05-19
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Add `application/vnd.balsamiq.bmpr`
|
|
||||||
* Add `application/vnd.microsoft.portable-executable`
|
|
||||||
* Add `application/x-ns-proxy-autoconfig`
|
|
||||||
|
|
||||||
1.9.1 / 2015-04-19
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Remove `.json` extension from `application/manifest+json`
|
|
||||||
- This is causing bugs downstream
|
|
||||||
|
|
||||||
1.9.0 / 2015-04-19
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/manifest+json`
|
|
||||||
* Add `application/vnd.micro+json`
|
|
||||||
* Add `image/vnd.zbrush.pcx`
|
|
||||||
* Add `image/x-ms-bmp`
|
|
||||||
|
|
||||||
1.8.0 / 2015-03-13
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/vnd.citationstyles.style+xml`
|
|
||||||
* Add `application/vnd.fastcopy-disk-image`
|
|
||||||
* Add `application/vnd.gov.sk.xmldatacontainer+xml`
|
|
||||||
* Add extension `.jsonld` to `application/ld+json`
|
|
||||||
|
|
||||||
1.7.0 / 2015-02-08
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/vnd.gerber`
|
|
||||||
* Add `application/vnd.msa-disk-image`
|
|
||||||
|
|
||||||
1.6.1 / 2015-02-05
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Community extensions ownership transferred from `node-mime`
|
|
||||||
|
|
||||||
1.6.0 / 2015-01-29
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/jose`
|
|
||||||
* Add `application/jose+json`
|
|
||||||
* Add `application/json-seq`
|
|
||||||
* Add `application/jwk+json`
|
|
||||||
* Add `application/jwk-set+json`
|
|
||||||
* Add `application/jwt`
|
|
||||||
* Add `application/rdap+json`
|
|
||||||
* Add `application/vnd.gov.sk.e-form+xml`
|
|
||||||
* Add `application/vnd.ims.imsccv1p3`
|
|
||||||
|
|
||||||
1.5.0 / 2014-12-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/vnd.oracle.resource+json`
|
|
||||||
* Fix various invalid MIME type entries
|
|
||||||
- `application/mbox+xml`
|
|
||||||
- `application/oscp-response`
|
|
||||||
- `application/vwg-multiplexed`
|
|
||||||
- `audio/g721`
|
|
||||||
|
|
||||||
1.4.0 / 2014-12-21
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/vnd.ims.imsccv1p2`
|
|
||||||
* Fix various invalid MIME type entries
|
|
||||||
- `application/vnd-acucobol`
|
|
||||||
- `application/vnd-curl`
|
|
||||||
- `application/vnd-dart`
|
|
||||||
- `application/vnd-dxr`
|
|
||||||
- `application/vnd-fdf`
|
|
||||||
- `application/vnd-mif`
|
|
||||||
- `application/vnd-sema`
|
|
||||||
- `application/vnd-wap-wmlc`
|
|
||||||
- `application/vnd.adobe.flash-movie`
|
|
||||||
- `application/vnd.dece-zip`
|
|
||||||
- `application/vnd.dvb_service`
|
|
||||||
- `application/vnd.micrografx-igx`
|
|
||||||
- `application/vnd.sealed-doc`
|
|
||||||
- `application/vnd.sealed-eml`
|
|
||||||
- `application/vnd.sealed-mht`
|
|
||||||
- `application/vnd.sealed-ppt`
|
|
||||||
- `application/vnd.sealed-tiff`
|
|
||||||
- `application/vnd.sealed-xls`
|
|
||||||
- `application/vnd.sealedmedia.softseal-html`
|
|
||||||
- `application/vnd.sealedmedia.softseal-pdf`
|
|
||||||
- `application/vnd.wap-slc`
|
|
||||||
- `application/vnd.wap-wbxml`
|
|
||||||
- `audio/vnd.sealedmedia.softseal-mpeg`
|
|
||||||
- `image/vnd-djvu`
|
|
||||||
- `image/vnd-svf`
|
|
||||||
- `image/vnd-wap-wbmp`
|
|
||||||
- `image/vnd.sealed-png`
|
|
||||||
- `image/vnd.sealedmedia.softseal-gif`
|
|
||||||
- `image/vnd.sealedmedia.softseal-jpg`
|
|
||||||
- `model/vnd-dwf`
|
|
||||||
- `model/vnd.parasolid.transmit-binary`
|
|
||||||
- `model/vnd.parasolid.transmit-text`
|
|
||||||
- `text/vnd-a`
|
|
||||||
- `text/vnd-curl`
|
|
||||||
- `text/vnd.wap-wml`
|
|
||||||
* Remove example template MIME types
|
|
||||||
- `application/example`
|
|
||||||
- `audio/example`
|
|
||||||
- `image/example`
|
|
||||||
- `message/example`
|
|
||||||
- `model/example`
|
|
||||||
- `multipart/example`
|
|
||||||
- `text/example`
|
|
||||||
- `video/example`
|
|
||||||
|
|
||||||
1.3.1 / 2014-12-16
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Fix missing extensions
|
|
||||||
- `application/json5`
|
|
||||||
- `text/hjson`
|
|
||||||
|
|
||||||
1.3.0 / 2014-12-07
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/a2l`
|
|
||||||
* Add `application/aml`
|
|
||||||
* Add `application/atfx`
|
|
||||||
* Add `application/atxml`
|
|
||||||
* Add `application/cdfx+xml`
|
|
||||||
* Add `application/dii`
|
|
||||||
* Add `application/json5`
|
|
||||||
* Add `application/lxf`
|
|
||||||
* Add `application/mf4`
|
|
||||||
* Add `application/vnd.apache.thrift.compact`
|
|
||||||
* Add `application/vnd.apache.thrift.json`
|
|
||||||
* Add `application/vnd.coffeescript`
|
|
||||||
* Add `application/vnd.enphase.envoy`
|
|
||||||
* Add `application/vnd.ims.imsccv1p1`
|
|
||||||
* Add `text/csv-schema`
|
|
||||||
* Add `text/hjson`
|
|
||||||
* Add `text/markdown`
|
|
||||||
* Add `text/yaml`
|
|
||||||
|
|
||||||
1.2.0 / 2014-11-09
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/cea`
|
|
||||||
* Add `application/dit`
|
|
||||||
* Add `application/vnd.gov.sk.e-form+zip`
|
|
||||||
* Add `application/vnd.tmd.mediaflex.api+xml`
|
|
||||||
* Type `application/epub+zip` is now IANA-registered
|
|
||||||
|
|
||||||
1.1.2 / 2014-10-23
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Rebuild database for `application/x-www-form-urlencoded` change
|
|
||||||
|
|
||||||
1.1.1 / 2014-10-20
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Mark `application/x-www-form-urlencoded` as compressible.
|
|
||||||
|
|
||||||
1.1.0 / 2014-09-28
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/font-woff2`
|
|
||||||
|
|
||||||
1.0.3 / 2014-09-25
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Fix engine requirement in package
|
|
||||||
|
|
||||||
1.0.2 / 2014-09-25
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/coap-group+json`
|
|
||||||
* Add `application/dcd`
|
|
||||||
* Add `application/vnd.apache.thrift.binary`
|
|
||||||
* Add `image/vnd.tencent.tap`
|
|
||||||
* Mark all JSON-derived types as compressible
|
|
||||||
* Update `text/vtt` data
|
|
||||||
|
|
||||||
1.0.1 / 2014-08-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Fix extension ordering
|
|
||||||
|
|
||||||
1.0.0 / 2014-08-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `application/atf`
|
|
||||||
* Add `application/merge-patch+json`
|
|
||||||
* Add `multipart/x-mixed-replace`
|
|
||||||
* Add `source: 'apache'` metadata
|
|
||||||
* Add `source: 'iana'` metadata
|
|
||||||
* Remove badly-assumed charset data
|
|
@ -1,23 +0,0 @@
|
|||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
|
|
||||||
Copyright (c) 2015-2022 Douglas Christopher Wilson <doug@somethingdoug.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
'Software'), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,100 +0,0 @@
|
|||||||
# mime-db
|
|
||||||
|
|
||||||
[![NPM Version][npm-version-image]][npm-url]
|
|
||||||
[![NPM Downloads][npm-downloads-image]][npm-url]
|
|
||||||
[![Node.js Version][node-image]][node-url]
|
|
||||||
[![Build Status][ci-image]][ci-url]
|
|
||||||
[![Coverage Status][coveralls-image]][coveralls-url]
|
|
||||||
|
|
||||||
This is a large database of mime types and information about them.
|
|
||||||
It consists of a single, public JSON file and does not include any logic,
|
|
||||||
allowing it to remain as un-opinionated as possible with an API.
|
|
||||||
It aggregates data from the following sources:
|
|
||||||
|
|
||||||
- http://www.iana.org/assignments/media-types/media-types.xhtml
|
|
||||||
- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
|
|
||||||
- http://hg.nginx.org/nginx/raw-file/default/conf/mime.types
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install mime-db
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Download
|
|
||||||
|
|
||||||
If you're crazy enough to use this in the browser, you can just grab the
|
|
||||||
JSON file using [jsDelivr](https://www.jsdelivr.com/). It is recommended to
|
|
||||||
replace `master` with [a release tag](https://github.com/jshttp/mime-db/tags)
|
|
||||||
as the JSON format may change in the future.
|
|
||||||
|
|
||||||
```
|
|
||||||
https://cdn.jsdelivr.net/gh/jshttp/mime-db@master/db.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
var db = require('mime-db')
|
|
||||||
|
|
||||||
// grab data on .js files
|
|
||||||
var data = db['application/javascript']
|
|
||||||
```
|
|
||||||
|
|
||||||
## Data Structure
|
|
||||||
|
|
||||||
The JSON file is a map lookup for lowercased mime types.
|
|
||||||
Each mime type has the following properties:
|
|
||||||
|
|
||||||
- `.source` - where the mime type is defined.
|
|
||||||
If not set, it's probably a custom media type.
|
|
||||||
- `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
|
|
||||||
- `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)
|
|
||||||
- `nginx` - [nginx media types](http://hg.nginx.org/nginx/raw-file/default/conf/mime.types)
|
|
||||||
- `.extensions[]` - known extensions associated with this mime type.
|
|
||||||
- `.compressible` - whether a file of this type can be gzipped.
|
|
||||||
- `.charset` - the default charset associated with this type, if any.
|
|
||||||
|
|
||||||
If unknown, every property could be `undefined`.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
To edit the database, only make PRs against `src/custom-types.json` or
|
|
||||||
`src/custom-suffix.json`.
|
|
||||||
|
|
||||||
The `src/custom-types.json` file is a JSON object with the MIME type as the
|
|
||||||
keys and the values being an object with the following keys:
|
|
||||||
|
|
||||||
- `compressible` - leave out if you don't know, otherwise `true`/`false` to
|
|
||||||
indicate whether the data represented by the type is typically compressible.
|
|
||||||
- `extensions` - include an array of file extensions that are associated with
|
|
||||||
the type.
|
|
||||||
- `notes` - human-readable notes about the type, typically what the type is.
|
|
||||||
- `sources` - include an array of URLs of where the MIME type and the associated
|
|
||||||
extensions are sourced from. This needs to be a [primary source](https://en.wikipedia.org/wiki/Primary_source);
|
|
||||||
links to type aggregating sites and Wikipedia are _not acceptable_.
|
|
||||||
|
|
||||||
To update the build, run `npm run build`.
|
|
||||||
|
|
||||||
### Adding Custom Media Types
|
|
||||||
|
|
||||||
The best way to get new media types included in this library is to register
|
|
||||||
them with the IANA. The community registration procedure is outlined in
|
|
||||||
[RFC 6838 section 5](http://tools.ietf.org/html/rfc6838#section-5). Types
|
|
||||||
registered with the IANA are automatically pulled into this library.
|
|
||||||
|
|
||||||
If that is not possible / feasible, they can be added directly here as a
|
|
||||||
"custom" type. To do this, it is required to have a primary source that
|
|
||||||
definitively lists the media type. If an extension is going to be listed as
|
|
||||||
associateed with this media type, the source must definitively link the
|
|
||||||
media type and extension as well.
|
|
||||||
|
|
||||||
[ci-image]: https://badgen.net/github/checks/jshttp/mime-db/master?label=ci
|
|
||||||
[ci-url]: https://github.com/jshttp/mime-db/actions?query=workflow%3Aci
|
|
||||||
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-db/master
|
|
||||||
[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
|
|
||||||
[node-image]: https://badgen.net/npm/node/mime-db
|
|
||||||
[node-url]: https://nodejs.org/en/download
|
|
||||||
[npm-downloads-image]: https://badgen.net/npm/dm/mime-db
|
|
||||||
[npm-url]: https://npmjs.org/package/mime-db
|
|
||||||
[npm-version-image]: https://badgen.net/npm/v/mime-db
|
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
|||||||
/*!
|
|
||||||
* mime-db
|
|
||||||
* Copyright(c) 2014 Jonathan Ong
|
|
||||||
* Copyright(c) 2015-2022 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module exports.
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = require('./db.json')
|
|
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mime-db",
|
|
||||||
"description": "Media Type Database",
|
|
||||||
"version": "1.52.0",
|
|
||||||
"contributors": [
|
|
||||||
"Douglas Christopher Wilson <doug@somethingdoug.com>",
|
|
||||||
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)",
|
|
||||||
"Robert Kieffer <robert@broofa.com> (http://github.com/broofa)"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"mime",
|
|
||||||
"db",
|
|
||||||
"type",
|
|
||||||
"types",
|
|
||||||
"database",
|
|
||||||
"charset",
|
|
||||||
"charsets"
|
|
||||||
],
|
|
||||||
"repository": "jshttp/mime-db",
|
|
||||||
"devDependencies": {
|
|
||||||
"bluebird": "3.7.2",
|
|
||||||
"co": "4.6.0",
|
|
||||||
"cogent": "1.0.1",
|
|
||||||
"csv-parse": "4.16.3",
|
|
||||||
"eslint": "7.32.0",
|
|
||||||
"eslint-config-standard": "15.0.1",
|
|
||||||
"eslint-plugin-import": "2.25.4",
|
|
||||||
"eslint-plugin-markdown": "2.2.1",
|
|
||||||
"eslint-plugin-node": "11.1.0",
|
|
||||||
"eslint-plugin-promise": "5.1.1",
|
|
||||||
"eslint-plugin-standard": "4.1.0",
|
|
||||||
"gnode": "0.1.2",
|
|
||||||
"media-typer": "1.1.0",
|
|
||||||
"mocha": "9.2.1",
|
|
||||||
"nyc": "15.1.0",
|
|
||||||
"raw-body": "2.5.0",
|
|
||||||
"stream-to-array": "2.3.0"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"HISTORY.md",
|
|
||||||
"LICENSE",
|
|
||||||
"README.md",
|
|
||||||
"db.json",
|
|
||||||
"index.js"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "node scripts/build",
|
|
||||||
"fetch": "node scripts/fetch-apache && gnode scripts/fetch-iana && node scripts/fetch-nginx",
|
|
||||||
"lint": "eslint .",
|
|
||||||
"test": "mocha --reporter spec --bail --check-leaks test/",
|
|
||||||
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
|
|
||||||
"test-cov": "nyc --reporter=html --reporter=text npm test",
|
|
||||||
"update": "npm run fetch && npm run build",
|
|
||||||
"version": "node scripts/version-history.js && git add HISTORY.md"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,397 +0,0 @@
|
|||||||
2.1.35 / 2022-03-12
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.52.0
|
|
||||||
- Add extensions from IANA for more `image/*` types
|
|
||||||
- Add extension `.asc` to `application/pgp-keys`
|
|
||||||
- Add extensions to various XML types
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.34 / 2021-11-08
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.51.0
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.33 / 2021-10-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.50.0
|
|
||||||
- Add deprecated iWorks mime types and extensions
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.32 / 2021-07-27
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.49.0
|
|
||||||
- Add extension `.trig` to `application/trig`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.31 / 2021-06-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.48.0
|
|
||||||
- Add extension `.mvt` to `application/vnd.mapbox-vector-tile`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.30 / 2021-04-02
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.47.0
|
|
||||||
- Add extension `.amr` to `audio/amr`
|
|
||||||
- Remove ambigious extensions from IANA for `application/*+xml` types
|
|
||||||
- Update primary extension to `.es` for `application/ecmascript`
|
|
||||||
|
|
||||||
2.1.29 / 2021-02-17
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.46.0
|
|
||||||
- Add extension `.amr` to `audio/amr`
|
|
||||||
- Add extension `.m4s` to `video/iso.segment`
|
|
||||||
- Add extension `.opus` to `audio/ogg`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.28 / 2021-01-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.45.0
|
|
||||||
- Add `application/ubjson` with extension `.ubj`
|
|
||||||
- Add `image/avif` with extension `.avif`
|
|
||||||
- Add `image/ktx2` with extension `.ktx2`
|
|
||||||
- Add extension `.dbf` to `application/vnd.dbf`
|
|
||||||
- Add extension `.rar` to `application/vnd.rar`
|
|
||||||
- Add extension `.td` to `application/urc-targetdesc+xml`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
- Fix extension of `application/vnd.apple.keynote` to be `.key`
|
|
||||||
|
|
||||||
2.1.27 / 2020-04-23
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.44.0
|
|
||||||
- Add charsets from IANA
|
|
||||||
- Add extension `.cjs` to `application/node`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.26 / 2020-01-05
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.43.0
|
|
||||||
- Add `application/x-keepass2` with extension `.kdbx`
|
|
||||||
- Add extension `.mxmf` to `audio/mobile-xmf`
|
|
||||||
- Add extensions from IANA for `application/*+xml` types
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.25 / 2019-11-12
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.42.0
|
|
||||||
- Add new upstream MIME types
|
|
||||||
- Add `application/toml` with extension `.toml`
|
|
||||||
- Add `image/vnd.ms-dds` with extension `.dds`
|
|
||||||
|
|
||||||
2.1.24 / 2019-04-20
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@1.40.0
|
|
||||||
- Add extensions from IANA for `model/*` types
|
|
||||||
- Add `text/mdx` with extension `.mdx`
|
|
||||||
|
|
||||||
2.1.23 / 2019-04-17
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.39.0
|
|
||||||
- Add extensions `.siv` and `.sieve` to `application/sieve`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.22 / 2019-02-14
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.38.0
|
|
||||||
- Add extension `.nq` to `application/n-quads`
|
|
||||||
- Add extension `.nt` to `application/n-triples`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.21 / 2018-10-19
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.37.0
|
|
||||||
- Add extensions to HEIC image types
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.20 / 2018-08-26
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.36.0
|
|
||||||
- Add Apple file extensions from IANA
|
|
||||||
- Add extensions from IANA for `image/*` types
|
|
||||||
- Add new upstream MIME types
|
|
||||||
|
|
||||||
2.1.19 / 2018-07-17
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.35.0
|
|
||||||
- Add extension `.csl` to `application/vnd.citationstyles.style+xml`
|
|
||||||
- Add extension `.es` to `application/ecmascript`
|
|
||||||
- Add extension `.owl` to `application/rdf+xml`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
- Add UTF-8 as default charset for `text/turtle`
|
|
||||||
|
|
||||||
2.1.18 / 2018-02-16
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.33.0
|
|
||||||
- Add `application/raml+yaml` with extension `.raml`
|
|
||||||
- Add `application/wasm` with extension `.wasm`
|
|
||||||
- Add `text/shex` with extension `.shex`
|
|
||||||
- Add extensions for JPEG-2000 images
|
|
||||||
- Add extensions from IANA for `message/*` types
|
|
||||||
- Add new upstream MIME types
|
|
||||||
- Update font MIME types
|
|
||||||
- Update `text/hjson` to registered `application/hjson`
|
|
||||||
|
|
||||||
2.1.17 / 2017-09-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.30.0
|
|
||||||
- Add `application/vnd.ms-outlook`
|
|
||||||
- Add `application/x-arj`
|
|
||||||
- Add extension `.mjs` to `application/javascript`
|
|
||||||
- Add glTF types and extensions
|
|
||||||
- Add new upstream MIME types
|
|
||||||
- Add `text/x-org`
|
|
||||||
- Add VirtualBox MIME types
|
|
||||||
- Fix `source` records for `video/*` types that are IANA
|
|
||||||
- Update `font/opentype` to registered `font/otf`
|
|
||||||
|
|
||||||
2.1.16 / 2017-07-24
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.29.0
|
|
||||||
- Add `application/fido.trusted-apps+json`
|
|
||||||
- Add extension `.wadl` to `application/vnd.sun.wadl+xml`
|
|
||||||
- Add extension `.gz` to `application/gzip`
|
|
||||||
- Add new upstream MIME types
|
|
||||||
- Update extensions `.md` and `.markdown` to be `text/markdown`
|
|
||||||
|
|
||||||
2.1.15 / 2017-03-23
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.27.0
|
|
||||||
- Add new mime types
|
|
||||||
- Add `image/apng`
|
|
||||||
|
|
||||||
2.1.14 / 2017-01-14
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.26.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.13 / 2016-11-18
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.25.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.12 / 2016-09-18
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.24.0
|
|
||||||
- Add new mime types
|
|
||||||
- Add `audio/mp3`
|
|
||||||
|
|
||||||
2.1.11 / 2016-05-01
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.23.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.10 / 2016-02-15
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.22.0
|
|
||||||
- Add new mime types
|
|
||||||
- Fix extension of `application/dash+xml`
|
|
||||||
- Update primary extension for `audio/mp4`
|
|
||||||
|
|
||||||
2.1.9 / 2016-01-06
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.21.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.8 / 2015-11-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.20.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.7 / 2015-09-20
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.19.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.6 / 2015-09-03
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.18.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.5 / 2015-08-20
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.17.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.4 / 2015-07-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.16.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.3 / 2015-07-13
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.15.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.2 / 2015-06-25
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.14.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.1.1 / 2015-06-08
|
|
||||||
==================
|
|
||||||
|
|
||||||
* perf: fix deopt during mapping
|
|
||||||
|
|
||||||
2.1.0 / 2015-06-07
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Fix incorrectly treating extension-less file name as extension
|
|
||||||
- i.e. `'path/to/json'` will no longer return `application/json`
|
|
||||||
* Fix `.charset(type)` to accept parameters
|
|
||||||
* Fix `.charset(type)` to match case-insensitive
|
|
||||||
* Improve generation of extension to MIME mapping
|
|
||||||
* Refactor internals for readability and no argument reassignment
|
|
||||||
* Prefer `application/*` MIME types from the same source
|
|
||||||
* Prefer any type over `application/octet-stream`
|
|
||||||
* deps: mime-db@~1.13.0
|
|
||||||
- Add nginx as a source
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.14 / 2015-06-06
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.12.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.13 / 2015-05-31
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.11.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.12 / 2015-05-19
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.10.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.11 / 2015-05-05
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.9.1
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.10 / 2015-03-13
|
|
||||||
===================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.8.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.9 / 2015-02-09
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.7.0
|
|
||||||
- Add new mime types
|
|
||||||
- Community extensions ownership transferred from `node-mime`
|
|
||||||
|
|
||||||
2.0.8 / 2015-01-29
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.6.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.7 / 2014-12-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.5.0
|
|
||||||
- Add new mime types
|
|
||||||
- Fix various invalid MIME type entries
|
|
||||||
|
|
||||||
2.0.6 / 2014-12-30
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.4.0
|
|
||||||
- Add new mime types
|
|
||||||
- Fix various invalid MIME type entries
|
|
||||||
- Remove example template MIME types
|
|
||||||
|
|
||||||
2.0.5 / 2014-12-29
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.3.1
|
|
||||||
- Fix missing extensions
|
|
||||||
|
|
||||||
2.0.4 / 2014-12-10
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.3.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.3 / 2014-11-09
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.2.0
|
|
||||||
- Add new mime types
|
|
||||||
|
|
||||||
2.0.2 / 2014-09-28
|
|
||||||
==================
|
|
||||||
|
|
||||||
* deps: mime-db@~1.1.0
|
|
||||||
- Add new mime types
|
|
||||||
- Update charsets
|
|
||||||
|
|
||||||
2.0.1 / 2014-09-07
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Support Node.js 0.6
|
|
||||||
|
|
||||||
2.0.0 / 2014-09-02
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Use `mime-db`
|
|
||||||
* Remove `.define()`
|
|
||||||
|
|
||||||
1.0.2 / 2014-08-04
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Set charset=utf-8 for `text/javascript`
|
|
||||||
|
|
||||||
1.0.1 / 2014-06-24
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Add `text/jsx` type
|
|
||||||
|
|
||||||
1.0.0 / 2014-05-12
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Return `false` for unknown types
|
|
||||||
* Set charset=utf-8 for `application/json`
|
|
||||||
|
|
||||||
0.1.0 / 2014-05-02
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Initial release
|
|
@ -1,23 +0,0 @@
|
|||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
|
|
||||||
Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
'Software'), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,113 +0,0 @@
|
|||||||
# mime-types
|
|
||||||
|
|
||||||
[![NPM Version][npm-version-image]][npm-url]
|
|
||||||
[![NPM Downloads][npm-downloads-image]][npm-url]
|
|
||||||
[![Node.js Version][node-version-image]][node-version-url]
|
|
||||||
[![Build Status][ci-image]][ci-url]
|
|
||||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
||||||
|
|
||||||
The ultimate javascript content-type utility.
|
|
||||||
|
|
||||||
Similar to [the `mime@1.x` module](https://www.npmjs.com/package/mime), except:
|
|
||||||
|
|
||||||
- __No fallbacks.__ Instead of naively returning the first available type,
|
|
||||||
`mime-types` simply returns `false`, so do
|
|
||||||
`var type = mime.lookup('unrecognized') || 'application/octet-stream'`.
|
|
||||||
- No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`.
|
|
||||||
- No `.define()` functionality
|
|
||||||
- Bug fixes for `.lookup(path)`
|
|
||||||
|
|
||||||
Otherwise, the API is compatible with `mime` 1.x.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
This is a [Node.js](https://nodejs.org/en/) module available through the
|
|
||||||
[npm registry](https://www.npmjs.com/). Installation is done using the
|
|
||||||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm install mime-types
|
|
||||||
```
|
|
||||||
|
|
||||||
## Adding Types
|
|
||||||
|
|
||||||
All mime types are based on [mime-db](https://www.npmjs.com/package/mime-db),
|
|
||||||
so open a PR there if you'd like to add mime types.
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```js
|
|
||||||
var mime = require('mime-types')
|
|
||||||
```
|
|
||||||
|
|
||||||
All functions return `false` if input is invalid or not found.
|
|
||||||
|
|
||||||
### mime.lookup(path)
|
|
||||||
|
|
||||||
Lookup the content-type associated with a file.
|
|
||||||
|
|
||||||
```js
|
|
||||||
mime.lookup('json') // 'application/json'
|
|
||||||
mime.lookup('.md') // 'text/markdown'
|
|
||||||
mime.lookup('file.html') // 'text/html'
|
|
||||||
mime.lookup('folder/file.js') // 'application/javascript'
|
|
||||||
mime.lookup('folder/.htaccess') // false
|
|
||||||
|
|
||||||
mime.lookup('cats') // false
|
|
||||||
```
|
|
||||||
|
|
||||||
### mime.contentType(type)
|
|
||||||
|
|
||||||
Create a full content-type header given a content-type or extension.
|
|
||||||
When given an extension, `mime.lookup` is used to get the matching
|
|
||||||
content-type, otherwise the given content-type is used. Then if the
|
|
||||||
content-type does not already have a `charset` parameter, `mime.charset`
|
|
||||||
is used to get the default charset and add to the returned content-type.
|
|
||||||
|
|
||||||
```js
|
|
||||||
mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
|
|
||||||
mime.contentType('file.json') // 'application/json; charset=utf-8'
|
|
||||||
mime.contentType('text/html') // 'text/html; charset=utf-8'
|
|
||||||
mime.contentType('text/html; charset=iso-8859-1') // 'text/html; charset=iso-8859-1'
|
|
||||||
|
|
||||||
// from a full path
|
|
||||||
mime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8'
|
|
||||||
```
|
|
||||||
|
|
||||||
### mime.extension(type)
|
|
||||||
|
|
||||||
Get the default extension for a content-type.
|
|
||||||
|
|
||||||
```js
|
|
||||||
mime.extension('application/octet-stream') // 'bin'
|
|
||||||
```
|
|
||||||
|
|
||||||
### mime.charset(type)
|
|
||||||
|
|
||||||
Lookup the implied default charset of a content-type.
|
|
||||||
|
|
||||||
```js
|
|
||||||
mime.charset('text/markdown') // 'UTF-8'
|
|
||||||
```
|
|
||||||
|
|
||||||
### var type = mime.types[extension]
|
|
||||||
|
|
||||||
A map of content-types by extension.
|
|
||||||
|
|
||||||
### [extensions...] = mime.extensions[type]
|
|
||||||
|
|
||||||
A map of extensions by content-type.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[MIT](LICENSE)
|
|
||||||
|
|
||||||
[ci-image]: https://badgen.net/github/checks/jshttp/mime-types/master?label=ci
|
|
||||||
[ci-url]: https://github.com/jshttp/mime-types/actions/workflows/ci.yml
|
|
||||||
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-types/master
|
|
||||||
[coveralls-url]: https://coveralls.io/r/jshttp/mime-types?branch=master
|
|
||||||
[node-version-image]: https://badgen.net/npm/node/mime-types
|
|
||||||
[node-version-url]: https://nodejs.org/en/download
|
|
||||||
[npm-downloads-image]: https://badgen.net/npm/dm/mime-types
|
|
||||||
[npm-url]: https://npmjs.org/package/mime-types
|
|
||||||
[npm-version-image]: https://badgen.net/npm/v/mime-types
|
|
@ -1,188 +0,0 @@
|
|||||||
/*!
|
|
||||||
* mime-types
|
|
||||||
* Copyright(c) 2014 Jonathan Ong
|
|
||||||
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
var db = require('mime-db')
|
|
||||||
var extname = require('path').extname
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module variables.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/
|
|
||||||
var TEXT_TYPE_REGEXP = /^text\//i
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module exports.
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.charset = charset
|
|
||||||
exports.charsets = { lookup: charset }
|
|
||||||
exports.contentType = contentType
|
|
||||||
exports.extension = extension
|
|
||||||
exports.extensions = Object.create(null)
|
|
||||||
exports.lookup = lookup
|
|
||||||
exports.types = Object.create(null)
|
|
||||||
|
|
||||||
// Populate the extensions/types maps
|
|
||||||
populateMaps(exports.extensions, exports.types)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the default charset for a MIME type.
|
|
||||||
*
|
|
||||||
* @param {string} type
|
|
||||||
* @return {boolean|string}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function charset (type) {
|
|
||||||
if (!type || typeof type !== 'string') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use media-typer
|
|
||||||
var match = EXTRACT_TYPE_REGEXP.exec(type)
|
|
||||||
var mime = match && db[match[1].toLowerCase()]
|
|
||||||
|
|
||||||
if (mime && mime.charset) {
|
|
||||||
return mime.charset
|
|
||||||
}
|
|
||||||
|
|
||||||
// default text/* to utf-8
|
|
||||||
if (match && TEXT_TYPE_REGEXP.test(match[1])) {
|
|
||||||
return 'UTF-8'
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a full Content-Type header given a MIME type or extension.
|
|
||||||
*
|
|
||||||
* @param {string} str
|
|
||||||
* @return {boolean|string}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function contentType (str) {
|
|
||||||
// TODO: should this even be in this module?
|
|
||||||
if (!str || typeof str !== 'string') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var mime = str.indexOf('/') === -1
|
|
||||||
? exports.lookup(str)
|
|
||||||
: str
|
|
||||||
|
|
||||||
if (!mime) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use content-type or other module
|
|
||||||
if (mime.indexOf('charset') === -1) {
|
|
||||||
var charset = exports.charset(mime)
|
|
||||||
if (charset) mime += '; charset=' + charset.toLowerCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
return mime
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the default extension for a MIME type.
|
|
||||||
*
|
|
||||||
* @param {string} type
|
|
||||||
* @return {boolean|string}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function extension (type) {
|
|
||||||
if (!type || typeof type !== 'string') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use media-typer
|
|
||||||
var match = EXTRACT_TYPE_REGEXP.exec(type)
|
|
||||||
|
|
||||||
// get extensions
|
|
||||||
var exts = match && exports.extensions[match[1].toLowerCase()]
|
|
||||||
|
|
||||||
if (!exts || !exts.length) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return exts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup the MIME type for a file path/extension.
|
|
||||||
*
|
|
||||||
* @param {string} path
|
|
||||||
* @return {boolean|string}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function lookup (path) {
|
|
||||||
if (!path || typeof path !== 'string') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the extension ("ext" or ".ext" or full path)
|
|
||||||
var extension = extname('x.' + path)
|
|
||||||
.toLowerCase()
|
|
||||||
.substr(1)
|
|
||||||
|
|
||||||
if (!extension) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return exports.types[extension] || false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate the extensions and types maps.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function populateMaps (extensions, types) {
|
|
||||||
// source preference (least -> most)
|
|
||||||
var preference = ['nginx', 'apache', undefined, 'iana']
|
|
||||||
|
|
||||||
Object.keys(db).forEach(function forEachMimeType (type) {
|
|
||||||
var mime = db[type]
|
|
||||||
var exts = mime.extensions
|
|
||||||
|
|
||||||
if (!exts || !exts.length) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// mime -> extensions
|
|
||||||
extensions[type] = exts
|
|
||||||
|
|
||||||
// extension -> mime
|
|
||||||
for (var i = 0; i < exts.length; i++) {
|
|
||||||
var extension = exts[i]
|
|
||||||
|
|
||||||
if (types[extension]) {
|
|
||||||
var from = preference.indexOf(db[types[extension]].source)
|
|
||||||
var to = preference.indexOf(mime.source)
|
|
||||||
|
|
||||||
if (types[extension] !== 'application/octet-stream' &&
|
|
||||||
(from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {
|
|
||||||
// skip the remapping
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the extension -> mime
|
|
||||||
types[extension] = type
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mime-types",
|
|
||||||
"description": "The ultimate javascript content-type utility.",
|
|
||||||
"version": "2.1.35",
|
|
||||||
"contributors": [
|
|
||||||
"Douglas Christopher Wilson <doug@somethingdoug.com>",
|
|
||||||
"Jeremiah Senkpiel <fishrock123@rocketmail.com> (https://searchbeam.jit.su)",
|
|
||||||
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"mime",
|
|
||||||
"types"
|
|
||||||
],
|
|
||||||
"repository": "jshttp/mime-types",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-db": "1.52.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"eslint": "7.32.0",
|
|
||||||
"eslint-config-standard": "14.1.1",
|
|
||||||
"eslint-plugin-import": "2.25.4",
|
|
||||||
"eslint-plugin-markdown": "2.2.1",
|
|
||||||
"eslint-plugin-node": "11.1.0",
|
|
||||||
"eslint-plugin-promise": "5.2.0",
|
|
||||||
"eslint-plugin-standard": "4.1.0",
|
|
||||||
"mocha": "9.2.2",
|
|
||||||
"nyc": "15.1.0"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"HISTORY.md",
|
|
||||||
"LICENSE",
|
|
||||||
"index.js"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"lint": "eslint .",
|
|
||||||
"test": "mocha --reporter spec test/test.js",
|
|
||||||
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
|
|
||||||
"test-cov": "nyc --reporter=html --reporter=text npm test"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"root": true,
|
|
||||||
|
|
||||||
"extends": "@ljharb/eslint-config/node/0.4",
|
|
||||||
|
|
||||||
"rules": {
|
|
||||||
"array-bracket-spacing": 0,
|
|
||||||
"array-element-newline": 0,
|
|
||||||
"brace-style": 1,
|
|
||||||
"camelcase": 1,
|
|
||||||
"comma-dangle": 1,
|
|
||||||
"comma-spacing": 1,
|
|
||||||
"complexity": 0,
|
|
||||||
"curly": 1,
|
|
||||||
"dot-notation": 1,
|
|
||||||
"eol-last": 1,
|
|
||||||
"func-style": 1,
|
|
||||||
"function-paren-newline": 1,
|
|
||||||
"indent": [1, 4],
|
|
||||||
"key-spacing": 1,
|
|
||||||
"max-lines-per-function": 0,
|
|
||||||
"max-nested-callbacks": 1,
|
|
||||||
"max-statements": 0,
|
|
||||||
"multiline-comment-style": 1,
|
|
||||||
"no-array-constructor": 1,
|
|
||||||
"no-continue": 1,
|
|
||||||
"no-div-regex": 1,
|
|
||||||
"no-extra-parens": 1,
|
|
||||||
"no-mixed-operators": 1,
|
|
||||||
"no-multi-spaces": 1,
|
|
||||||
"no-multiple-empty-lines": 1,
|
|
||||||
"no-param-reassign": 1,
|
|
||||||
"no-plusplus": 1,
|
|
||||||
"no-proto": 1,
|
|
||||||
"no-redeclare": 1,
|
|
||||||
"no-restricted-syntax": 1,
|
|
||||||
"no-shadow": 1,
|
|
||||||
"no-trailing-spaces": 1,
|
|
||||||
"no-unused-vars": 1,
|
|
||||||
"no-use-before-define": 1,
|
|
||||||
"object-curly-newline": 1,
|
|
||||||
"object-curly-spacing": 1,
|
|
||||||
"operator-linebreak": 1,
|
|
||||||
"quote-props": 1,
|
|
||||||
"quotes": 1,
|
|
||||||
"semi-style": 1,
|
|
||||||
"semi": 1,
|
|
||||||
"space-before-blocks": 1,
|
|
||||||
"space-before-function-paren": 1,
|
|
||||||
"space-infix-ops": 1,
|
|
||||||
"strict": 1,
|
|
||||||
"wrap-regex": 1,
|
|
||||||
},
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: [ljharb]
|
|
||||||
patreon: # Replace with a single Patreon username
|
|
||||||
open_collective: # Replace with a single Open Collective username
|
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
|
||||||
tidelift: npm/minimist
|
|
||||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
||||||
liberapay: # Replace with a single Liberapay username
|
|
||||||
issuehunt: # Replace with a single IssueHunt username
|
|
||||||
otechie: # Replace with a single Otechie username
|
|
||||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"all": true,
|
|
||||||
"check-coverage": false,
|
|
||||||
"reporter": ["text-summary", "text", "html", "json"],
|
|
||||||
"lines": 86,
|
|
||||||
"statements": 85.93,
|
|
||||||
"functions": 82.43,
|
|
||||||
"branches": 76.06,
|
|
||||||
"exclude": [
|
|
||||||
"coverage",
|
|
||||||
"example",
|
|
||||||
"test"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,212 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
||||||
|
|
||||||
## [v1.2.7](https://github.com/minimistjs/minimist/compare/v1.2.6...v1.2.7) - 2022-10-10
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- [meta] add `auto-changelog` [`0ebf4eb`](https://github.com/minimistjs/minimist/commit/0ebf4ebcd5f7787a5524d31a849ef41316b83c3c)
|
|
||||||
- [actions] add reusable workflows [`e115b63`](https://github.com/minimistjs/minimist/commit/e115b63fa9d3909f33b00a2db647ff79068388de)
|
|
||||||
- [eslint] add eslint; rules to enable later are warnings [`f58745b`](https://github.com/minimistjs/minimist/commit/f58745b9bb84348e1be72af7dbba5840c7c13013)
|
|
||||||
- [Dev Deps] switch from `covert` to `nyc` [`ab03356`](https://github.com/minimistjs/minimist/commit/ab033567b9c8b31117cb026dc7f1e592ce455c65)
|
|
||||||
- [readme] rename and add badges [`236f4a0`](https://github.com/minimistjs/minimist/commit/236f4a07e4ebe5ee44f1496ec6974991ab293ffd)
|
|
||||||
- [meta] create FUNDING.yml; add `funding` in package.json [`783a49b`](https://github.com/minimistjs/minimist/commit/783a49bfd47e8335d3098a8cac75662cf71eb32a)
|
|
||||||
- [meta] use `npmignore` to autogenerate an npmignore file [`f81ece6`](https://github.com/minimistjs/minimist/commit/f81ece6aaec2fa14e69ff4f1e0407a8c4e2635a2)
|
|
||||||
- Only apps should have lockfiles [`56cad44`](https://github.com/minimistjs/minimist/commit/56cad44c7f879b9bb5ec18fcc349308024a89bfc)
|
|
||||||
- [Dev Deps] update `covert`, `tape`; remove unnecessary `tap` [`49c5f9f`](https://github.com/minimistjs/minimist/commit/49c5f9fb7e6a92db9eb340cc679de92fb3aacded)
|
|
||||||
- [Tests] add `aud` in `posttest` [`228ae93`](https://github.com/minimistjs/minimist/commit/228ae938f3cd9db9dfd8bd7458b076a7b2aef280)
|
|
||||||
- [meta] add `safe-publish-latest` [`01fc23f`](https://github.com/minimistjs/minimist/commit/01fc23f5104f85c75059972e01dd33796ab529ff)
|
|
||||||
- [meta] update repo URLs [`6b164c7`](https://github.com/minimistjs/minimist/commit/6b164c7d68e0b6bf32f894699effdfb7c63041dd)
|
|
||||||
|
|
||||||
## [v1.2.6](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.6) - 2022-03-21
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- test from prototype pollution PR [`bc8ecee`](https://github.com/minimistjs/minimist/commit/bc8ecee43875261f4f17eb20b1243d3ed15e70eb)
|
|
||||||
- isConstructorOrProto adapted from PR [`c2b9819`](https://github.com/minimistjs/minimist/commit/c2b981977fa834b223b408cfb860f933c9811e4d)
|
|
||||||
- security notice for additional prototype pollution issue [`ef88b93`](https://github.com/minimistjs/minimist/commit/ef88b9325f77b5ee643ccfc97e2ebda577e4c4e2)
|
|
||||||
|
|
||||||
## [v1.2.5](https://github.com/minimistjs/minimist/compare/v1.2.4...v1.2.5) - 2020-03-12
|
|
||||||
|
|
||||||
## [v1.2.4](https://github.com/minimistjs/minimist/compare/v1.2.3...v1.2.4) - 2020-03-11
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- security notice [`4cf1354`](https://github.com/minimistjs/minimist/commit/4cf1354839cb972e38496d35e12f806eea92c11f)
|
|
||||||
- additional test for constructor prototype pollution [`1043d21`](https://github.com/minimistjs/minimist/commit/1043d212c3caaf871966e710f52cfdf02f9eea4b)
|
|
||||||
|
|
||||||
## [v1.2.3](https://github.com/minimistjs/minimist/compare/v1.2.2...v1.2.3) - 2020-03-10
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- more failing proto pollution tests [`13c01a5`](https://github.com/minimistjs/minimist/commit/13c01a5327736903704984b7f65616b8476850cc)
|
|
||||||
- even more aggressive checks for protocol pollution [`38a4d1c`](https://github.com/minimistjs/minimist/commit/38a4d1caead72ef99e824bb420a2528eec03d9ab)
|
|
||||||
|
|
||||||
## [v1.2.2](https://github.com/minimistjs/minimist/compare/v1.2.1...v1.2.2) - 2020-03-10
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- failing test for protocol pollution [`0efed03`](https://github.com/minimistjs/minimist/commit/0efed0340ec8433638758f7ca0c77cb20a0bfbab)
|
|
||||||
- cleanup [`67d3722`](https://github.com/minimistjs/minimist/commit/67d3722413448d00a62963d2d30c34656a92d7e2)
|
|
||||||
- console.dir -> console.log [`47acf72`](https://github.com/minimistjs/minimist/commit/47acf72c715a630bf9ea013867f47f1dd69dfc54)
|
|
||||||
- don't assign onto __proto__ [`63e7ed0`](https://github.com/minimistjs/minimist/commit/63e7ed05aa4b1889ec2f3b196426db4500cbda94)
|
|
||||||
|
|
||||||
## [v1.2.1](https://github.com/minimistjs/minimist/compare/v1.2.0...v1.2.1) - 2020-03-10
|
|
||||||
|
|
||||||
### Merged
|
|
||||||
|
|
||||||
- move the `opts['--']` example back where it belongs [`#63`](https://github.com/minimistjs/minimist/pull/63)
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- add test [`6be5dae`](https://github.com/minimistjs/minimist/commit/6be5dae35a32a987bcf4137fcd6c19c5200ee909)
|
|
||||||
- fix bad boolean regexp [`ac3fc79`](https://github.com/minimistjs/minimist/commit/ac3fc796e63b95128fdbdf67ea7fad71bd59aa76)
|
|
||||||
|
|
||||||
## [v1.2.0](https://github.com/minimistjs/minimist/compare/v1.1.3...v1.2.0) - 2015-08-24
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- failing -k=v short test [`63416b8`](https://github.com/minimistjs/minimist/commit/63416b8cd1d0d70e4714564cce465a36e4dd26d7)
|
|
||||||
- kv short fix [`6bbe145`](https://github.com/minimistjs/minimist/commit/6bbe14529166245e86424f220a2321442fe88dc3)
|
|
||||||
- failing kv short test [`f72ab7f`](https://github.com/minimistjs/minimist/commit/f72ab7f4572adc52902c9b6873cc969192f01b10)
|
|
||||||
- fixed kv test [`f5a48c3`](https://github.com/minimistjs/minimist/commit/f5a48c3e50e40ca54f00c8e84de4b4d6e9897fa8)
|
|
||||||
- enforce space between arg key and value [`86b321a`](https://github.com/minimistjs/minimist/commit/86b321affe648a8e016c095a4f0efa9d9074f502)
|
|
||||||
|
|
||||||
## [v1.1.3](https://github.com/minimistjs/minimist/compare/v1.1.2...v1.1.3) - 2015-08-06
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- add failing test - boolean alias array [`0fa3c5b`](https://github.com/minimistjs/minimist/commit/0fa3c5b3dd98551ddecf5392831b4c21211743fc)
|
|
||||||
- fix boolean values with multiple aliases [`9c0a6e7`](https://github.com/minimistjs/minimist/commit/9c0a6e7de25a273b11bbf9a7464f0bd833779795)
|
|
||||||
|
|
||||||
## [v1.1.2](https://github.com/minimistjs/minimist/compare/v1.1.1...v1.1.2) - 2015-07-22
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- Convert boolean arguments to boolean values [`8f3dc27`](https://github.com/minimistjs/minimist/commit/8f3dc27cf833f1d54671b6d0bcb55c2fe19672a9)
|
|
||||||
- use non-ancient npm, node 0.12 and iojs [`61ed1d0`](https://github.com/minimistjs/minimist/commit/61ed1d034b9ec7282764ce76f3992b1a0b4906ae)
|
|
||||||
- an older npm for 0.8 [`25cf778`](https://github.com/minimistjs/minimist/commit/25cf778b1220e7838a526832ad6972f75244054f)
|
|
||||||
|
|
||||||
## [v1.1.1](https://github.com/minimistjs/minimist/compare/v1.1.0...v1.1.1) - 2015-03-10
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- check that they type of a value is a boolean, not just that it is currently set to a boolean [`6863198`](https://github.com/minimistjs/minimist/commit/6863198e36139830ff1f20ffdceaddd93f2c1db9)
|
|
||||||
- upgrade tape, fix type issues from old tape version [`806712d`](https://github.com/minimistjs/minimist/commit/806712df91604ed02b8e39aa372b84aea659ee34)
|
|
||||||
- test for setting a boolean to a null default [`8c444fe`](https://github.com/minimistjs/minimist/commit/8c444fe89384ded7d441c120915ea60620b01dd3)
|
|
||||||
- if the previous value was a boolean, without an default (or with an alias) don't make an array either [`e5f419a`](https://github.com/minimistjs/minimist/commit/e5f419a3b5b3bc3f9e5ac71b7040621af70ed2dd)
|
|
||||||
|
|
||||||
## [v1.1.0](https://github.com/minimistjs/minimist/compare/v1.0.0...v1.1.0) - 2014-08-10
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- add support for handling "unknown" options not registered with the parser. [`6f3cc5d`](https://github.com/minimistjs/minimist/commit/6f3cc5d4e84524932a6ef2ce3592acc67cdd4383)
|
|
||||||
- reformat package.json [`02ed371`](https://github.com/minimistjs/minimist/commit/02ed37115194d3697ff358e8e25e5e66bab1d9f8)
|
|
||||||
- coverage script [`e5531ba`](https://github.com/minimistjs/minimist/commit/e5531ba0479da3b8138d3d8cac545d84ccb1c8df)
|
|
||||||
- extra fn to get 100% coverage again [`a6972da`](https://github.com/minimistjs/minimist/commit/a6972da89e56bf77642f8ec05a13b6558db93498)
|
|
||||||
|
|
||||||
## [v1.0.0](https://github.com/minimistjs/minimist/compare/v0.2.1...v1.0.0) - 2014-08-10
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- added stopEarly option [`471c7e4`](https://github.com/minimistjs/minimist/commit/471c7e4a7e910fc7ad8f9df850a186daf32c64e9)
|
|
||||||
- fix list [`fef6ae7`](https://github.com/minimistjs/minimist/commit/fef6ae79c38b9dc1c49569abb7cd04eb965eac5e)
|
|
||||||
|
|
||||||
## [v0.2.1](https://github.com/minimistjs/minimist/compare/v0.2.0...v0.2.1) - 2020-03-12
|
|
||||||
|
|
||||||
## [v0.2.0](https://github.com/minimistjs/minimist/compare/v0.1.0...v0.2.0) - 2014-06-19
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- support all-boolean mode [`450a97f`](https://github.com/minimistjs/minimist/commit/450a97f6e2bc85c7a4a13185c19a818d9a5ebe69)
|
|
||||||
|
|
||||||
## [v0.1.0](https://github.com/minimistjs/minimist/compare/v0.0.10...v0.1.0) - 2014-05-12
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- Provide a mechanism to segregate -- arguments [`ce4a1e6`](https://github.com/minimistjs/minimist/commit/ce4a1e63a7e8d5ab88d2a3768adefa6af98a445a)
|
|
||||||
- documented argv['--'] [`14db0e6`](https://github.com/minimistjs/minimist/commit/14db0e6dbc6d2b9e472adaa54dad7004b364634f)
|
|
||||||
- Adding a test-case for notFlags segregation [`715c1e3`](https://github.com/minimistjs/minimist/commit/715c1e3714be223f998f6c537af6b505f0236c16)
|
|
||||||
|
|
||||||
## [v0.0.10](https://github.com/minimistjs/minimist/compare/v0.0.9...v0.0.10) - 2014-05-11
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- dedicated boolean test [`46e448f`](https://github.com/minimistjs/minimist/commit/46e448f9f513cfeb2bcc8b688b9b47ba1e515c2b)
|
|
||||||
- dedicated num test [`9bf2d36`](https://github.com/minimistjs/minimist/commit/9bf2d36f1d3b8795be90b8f7de0a937f098aa394)
|
|
||||||
- aliased values treated as strings [`1ab743b`](https://github.com/minimistjs/minimist/commit/1ab743bad4484d69f1259bed42f9531de01119de)
|
|
||||||
- cover the case of already numbers, at 100% coverage [`b2bb044`](https://github.com/minimistjs/minimist/commit/b2bb04436599d77a2ce029e8e555e25b3aa55d13)
|
|
||||||
- another test for higher coverage [`3662624`](https://github.com/minimistjs/minimist/commit/3662624be976d5489d486a856849c048d13be903)
|
|
||||||
|
|
||||||
## [v0.0.9](https://github.com/minimistjs/minimist/compare/v0.0.8...v0.0.9) - 2014-05-08
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- Eliminate `longest` fn. [`824f642`](https://github.com/minimistjs/minimist/commit/824f642038d1b02ede68b6261d1d65163390929a)
|
|
||||||
|
|
||||||
## [v0.0.8](https://github.com/minimistjs/minimist/compare/v0.0.7...v0.0.8) - 2014-02-20
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- return '' if flag is string and empty [`fa63ed4`](https://github.com/minimistjs/minimist/commit/fa63ed4651a4ef4eefddce34188e0d98d745a263)
|
|
||||||
- handle joined single letters [`66c248f`](https://github.com/minimistjs/minimist/commit/66c248f0241d4d421d193b022e9e365f11178534)
|
|
||||||
|
|
||||||
## [v0.0.7](https://github.com/minimistjs/minimist/compare/v0.0.6...v0.0.7) - 2014-02-08
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- another swap of .test for .match [`d1da408`](https://github.com/minimistjs/minimist/commit/d1da40819acbe846d89a5c02721211e3c1260dde)
|
|
||||||
|
|
||||||
## [v0.0.6](https://github.com/minimistjs/minimist/compare/v0.0.5...v0.0.6) - 2014-02-08
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- use .test() instead of .match() to not crash on non-string values in the arguments array [`7e0d1ad`](https://github.com/minimistjs/minimist/commit/7e0d1add8c9e5b9b20a4d3d0f9a94d824c578da1)
|
|
||||||
|
|
||||||
## [v0.0.5](https://github.com/minimistjs/minimist/compare/v0.0.4...v0.0.5) - 2013-09-18
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- Improve '--' handling. [`b11822c`](https://github.com/minimistjs/minimist/commit/b11822c09cc9d2460f30384d12afc0b953c037a4)
|
|
||||||
|
|
||||||
## [v0.0.4](https://github.com/minimistjs/minimist/compare/v0.0.3...v0.0.4) - 2013-09-17
|
|
||||||
|
|
||||||
## [v0.0.3](https://github.com/minimistjs/minimist/compare/v0.0.2...v0.0.3) - 2013-09-12
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- failing test for single dash preceeding a double dash [`b465514`](https://github.com/minimistjs/minimist/commit/b465514b82c9ae28972d714facd951deb2ad762b)
|
|
||||||
- fix for the dot test [`6a095f1`](https://github.com/minimistjs/minimist/commit/6a095f1d364c8fab2d6753d2291a0649315d297a)
|
|
||||||
|
|
||||||
## [v0.0.2](https://github.com/minimistjs/minimist/compare/v0.0.1...v0.0.2) - 2013-08-28
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- allow dotted aliases & defaults [`321c33e`](https://github.com/minimistjs/minimist/commit/321c33e755485faaeb44eeb1c05d33b2e0a5a7c4)
|
|
||||||
- use a better version of ff [`e40f611`](https://github.com/minimistjs/minimist/commit/e40f61114cf7be6f7947f7b3eed345853a67dbbb)
|
|
||||||
|
|
||||||
## [v0.0.1](https://github.com/minimistjs/minimist/compare/v0.0.0...v0.0.1) - 2013-06-25
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- remove trailing commas [`6ff0fa0`](https://github.com/minimistjs/minimist/commit/6ff0fa055064f15dbe06d50b89d5173a6796e1db)
|
|
||||||
|
|
||||||
## v0.0.0 - 2013-06-25
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
|
|
||||||
- half of the parse test ported [`3079326`](https://github.com/minimistjs/minimist/commit/307932601325087de6cf94188eb798ffc4f3088a)
|
|
||||||
- stripped down code and a passing test from optimist [`7cced88`](https://github.com/minimistjs/minimist/commit/7cced88d82e399d1a03ed23eb667f04d3f320d10)
|
|
||||||
- ported parse tests completely over [`9448754`](https://github.com/minimistjs/minimist/commit/944875452e0820df6830b1408c26a0f7d3e1db04)
|
|
||||||
- docs, package.json [`a5bf46a`](https://github.com/minimistjs/minimist/commit/a5bf46ac9bb3bd114a9c340276c62c1091e538d5)
|
|
||||||
- move more short tests into short.js [`503edb5`](https://github.com/minimistjs/minimist/commit/503edb5c41d89c0d40831ee517154fc13b0f18b9)
|
|
||||||
- default bool test was wrong, not the code [`1b9f5db`](https://github.com/minimistjs/minimist/commit/1b9f5db4741b49962846081b68518de824992097)
|
|
||||||
- passing long tests ripped out of parse.js [`7972c4a`](https://github.com/minimistjs/minimist/commit/7972c4aff1f4803079e1668006658e2a761a0428)
|
|
||||||
- badges [`84c0370`](https://github.com/minimistjs/minimist/commit/84c037063664d42878aace715fe6572ce01b6f3b)
|
|
||||||
- all the tests now ported, some failures [`64239ed`](https://github.com/minimistjs/minimist/commit/64239edfe92c711c4eb0da254fcdfad2a5fdb605)
|
|
||||||
- failing short test [`f8a5341`](https://github.com/minimistjs/minimist/commit/f8a534112dd1138d2fad722def56a848480c446f)
|
|
||||||
- fixed the numeric test [`6b034f3`](https://github.com/minimistjs/minimist/commit/6b034f37c79342c60083ed97fd222e16928aac51)
|
|
@ -1,18 +0,0 @@
|
|||||||
This software is released under the MIT license:
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,117 +0,0 @@
|
|||||||
# minimist <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
|
|
||||||
|
|
||||||
[![github actions][actions-image]][actions-url]
|
|
||||||
[![coverage][codecov-image]][codecov-url]
|
|
||||||
[![License][license-image]][license-url]
|
|
||||||
[![Downloads][downloads-image]][downloads-url]
|
|
||||||
|
|
||||||
[![npm badge][npm-badge-png]][package-url]
|
|
||||||
|
|
||||||
parse argument options
|
|
||||||
|
|
||||||
This module is the guts of optimist's argument parser without all the
|
|
||||||
fanciful decoration.
|
|
||||||
|
|
||||||
# example
|
|
||||||
|
|
||||||
``` js
|
|
||||||
var argv = require('minimist')(process.argv.slice(2));
|
|
||||||
console.log(argv);
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
$ node example/parse.js -a beep -b boop
|
|
||||||
{ _: [], a: 'beep', b: 'boop' }
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
|
|
||||||
{ _: [ 'foo', 'bar', 'baz' ],
|
|
||||||
x: 3,
|
|
||||||
y: 4,
|
|
||||||
n: 5,
|
|
||||||
a: true,
|
|
||||||
b: true,
|
|
||||||
c: true,
|
|
||||||
beep: 'boop' }
|
|
||||||
```
|
|
||||||
|
|
||||||
# security
|
|
||||||
|
|
||||||
Previous versions had a prototype pollution bug that could cause privilege
|
|
||||||
escalation in some circumstances when handling untrusted user input.
|
|
||||||
|
|
||||||
Please use version 1.2.6 or later:
|
|
||||||
|
|
||||||
* https://security.snyk.io/vuln/SNYK-JS-MINIMIST-2429795 (version <=1.2.5)
|
|
||||||
* https://snyk.io/vuln/SNYK-JS-MINIMIST-559764 (version <=1.2.3)
|
|
||||||
|
|
||||||
# methods
|
|
||||||
|
|
||||||
``` js
|
|
||||||
var parseArgs = require('minimist')
|
|
||||||
```
|
|
||||||
|
|
||||||
## var argv = parseArgs(args, opts={})
|
|
||||||
|
|
||||||
Return an argument object `argv` populated with the array arguments from `args`.
|
|
||||||
|
|
||||||
`argv._` contains all the arguments that didn't have an option associated with
|
|
||||||
them.
|
|
||||||
|
|
||||||
Numeric-looking arguments will be returned as numbers unless `opts.string` or
|
|
||||||
`opts.boolean` is set for that argument name.
|
|
||||||
|
|
||||||
Any arguments after `'--'` will not be parsed and will end up in `argv._`.
|
|
||||||
|
|
||||||
options can be:
|
|
||||||
|
|
||||||
* `opts.string` - a string or array of strings argument names to always treat as
|
|
||||||
strings
|
|
||||||
* `opts.boolean` - a boolean, string or array of strings to always treat as
|
|
||||||
booleans. if `true` will treat all double hyphenated arguments without equal signs
|
|
||||||
as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`)
|
|
||||||
* `opts.alias` - an object mapping string names to strings or arrays of string
|
|
||||||
argument names to use as aliases
|
|
||||||
* `opts.default` - an object mapping string argument names to default values
|
|
||||||
* `opts.stopEarly` - when true, populate `argv._` with everything after the
|
|
||||||
first non-option
|
|
||||||
* `opts['--']` - when true, populate `argv._` with everything before the `--`
|
|
||||||
and `argv['--']` with everything after the `--`. Here's an example:
|
|
||||||
|
|
||||||
```
|
|
||||||
> require('./')('one two three -- four five --six'.split(' '), { '--': true })
|
|
||||||
{ _: [ 'one', 'two', 'three' ],
|
|
||||||
'--': [ 'four', 'five', '--six' ] }
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that with `opts['--']` set, parsing for arguments still stops after the
|
|
||||||
`--`.
|
|
||||||
|
|
||||||
* `opts.unknown` - a function which is invoked with a command line parameter not
|
|
||||||
defined in the `opts` configuration object. If the function returns `false`, the
|
|
||||||
unknown option is not added to `argv`.
|
|
||||||
|
|
||||||
# install
|
|
||||||
|
|
||||||
With [npm](https://npmjs.org) do:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install minimist
|
|
||||||
```
|
|
||||||
|
|
||||||
# license
|
|
||||||
|
|
||||||
MIT
|
|
||||||
|
|
||||||
[package-url]: https://npmjs.org/package/minimist
|
|
||||||
[npm-version-svg]: https://versionbadg.es/minimistjs/minimist.svg
|
|
||||||
[npm-badge-png]: https://nodei.co/npm/minimist.png?downloads=true&stars=true
|
|
||||||
[license-image]: https://img.shields.io/npm/l/minimist.svg
|
|
||||||
[license-url]: LICENSE
|
|
||||||
[downloads-image]: https://img.shields.io/npm/dm/minimist.svg
|
|
||||||
[downloads-url]: https://npm-stat.com/charts.html?package=minimist
|
|
||||||
[codecov-image]: https://codecov.io/gh/minimistjs/minimist/branch/main/graphs/badge.svg
|
|
||||||
[codecov-url]: https://app.codecov.io/gh/minimistjs/minimist/
|
|
||||||
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/minimistjs/minimist
|
|
||||||
[actions-url]: https://github.com/minimistjs/minimist/actions
|
|
@ -1,2 +0,0 @@
|
|||||||
var argv = require('../')(process.argv.slice(2));
|
|
||||||
console.log(argv);
|
|
@ -1,249 +0,0 @@
|
|||||||
module.exports = function (args, opts) {
|
|
||||||
if (!opts) opts = {};
|
|
||||||
|
|
||||||
var flags = { bools : {}, strings : {}, unknownFn: null };
|
|
||||||
|
|
||||||
if (typeof opts['unknown'] === 'function') {
|
|
||||||
flags.unknownFn = opts['unknown'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof opts['boolean'] === 'boolean' && opts['boolean']) {
|
|
||||||
flags.allBools = true;
|
|
||||||
} else {
|
|
||||||
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
|
|
||||||
flags.bools[key] = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var aliases = {};
|
|
||||||
Object.keys(opts.alias || {}).forEach(function (key) {
|
|
||||||
aliases[key] = [].concat(opts.alias[key]);
|
|
||||||
aliases[key].forEach(function (x) {
|
|
||||||
aliases[x] = [key].concat(aliases[key].filter(function (y) {
|
|
||||||
return x !== y;
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
[].concat(opts.string).filter(Boolean).forEach(function (key) {
|
|
||||||
flags.strings[key] = true;
|
|
||||||
if (aliases[key]) {
|
|
||||||
flags.strings[aliases[key]] = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var defaults = opts['default'] || {};
|
|
||||||
|
|
||||||
var argv = { _ : [] };
|
|
||||||
Object.keys(flags.bools).forEach(function (key) {
|
|
||||||
setArg(key, defaults[key] === undefined ? false : defaults[key]);
|
|
||||||
});
|
|
||||||
|
|
||||||
var notFlags = [];
|
|
||||||
|
|
||||||
if (args.indexOf('--') !== -1) {
|
|
||||||
notFlags = args.slice(args.indexOf('--')+1);
|
|
||||||
args = args.slice(0, args.indexOf('--'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function argDefined(key, arg) {
|
|
||||||
return (flags.allBools && /^--[^=]+$/.test(arg)) ||
|
|
||||||
flags.strings[key] || flags.bools[key] || aliases[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
function setArg (key, val, arg) {
|
|
||||||
if (arg && flags.unknownFn && !argDefined(key, arg)) {
|
|
||||||
if (flags.unknownFn(arg) === false) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = !flags.strings[key] && isNumber(val)
|
|
||||||
? Number(val) : val
|
|
||||||
;
|
|
||||||
setKey(argv, key.split('.'), value);
|
|
||||||
|
|
||||||
(aliases[key] || []).forEach(function (x) {
|
|
||||||
setKey(argv, x.split('.'), value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setKey (obj, keys, value) {
|
|
||||||
var o = obj;
|
|
||||||
for (var i = 0; i < keys.length-1; i++) {
|
|
||||||
var key = keys[i];
|
|
||||||
if (isConstructorOrProto(o, key)) return;
|
|
||||||
if (o[key] === undefined) o[key] = {};
|
|
||||||
if (o[key] === Object.prototype || o[key] === Number.prototype
|
|
||||||
|| o[key] === String.prototype) o[key] = {};
|
|
||||||
if (o[key] === Array.prototype) o[key] = [];
|
|
||||||
o = o[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = keys[keys.length - 1];
|
|
||||||
if (isConstructorOrProto(o, key)) return;
|
|
||||||
if (o === Object.prototype || o === Number.prototype
|
|
||||||
|| o === String.prototype) o = {};
|
|
||||||
if (o === Array.prototype) o = [];
|
|
||||||
if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') {
|
|
||||||
o[key] = value;
|
|
||||||
}
|
|
||||||
else if (Array.isArray(o[key])) {
|
|
||||||
o[key].push(value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
o[key] = [ o[key], value ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function aliasIsBoolean(key) {
|
|
||||||
return aliases[key].some(function (x) {
|
|
||||||
return flags.bools[x];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < args.length; i++) {
|
|
||||||
var arg = args[i];
|
|
||||||
|
|
||||||
if (/^--.+=/.test(arg)) {
|
|
||||||
// Using [\s\S] instead of . because js doesn't support the
|
|
||||||
// 'dotall' regex modifier. See:
|
|
||||||
// http://stackoverflow.com/a/1068308/13216
|
|
||||||
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
|
|
||||||
var key = m[1];
|
|
||||||
var value = m[2];
|
|
||||||
if (flags.bools[key]) {
|
|
||||||
value = value !== 'false';
|
|
||||||
}
|
|
||||||
setArg(key, value, arg);
|
|
||||||
}
|
|
||||||
else if (/^--no-.+/.test(arg)) {
|
|
||||||
var key = arg.match(/^--no-(.+)/)[1];
|
|
||||||
setArg(key, false, arg);
|
|
||||||
}
|
|
||||||
else if (/^--.+/.test(arg)) {
|
|
||||||
var key = arg.match(/^--(.+)/)[1];
|
|
||||||
var next = args[i + 1];
|
|
||||||
if (next !== undefined && !/^-/.test(next)
|
|
||||||
&& !flags.bools[key]
|
|
||||||
&& !flags.allBools
|
|
||||||
&& (aliases[key] ? !aliasIsBoolean(key) : true)) {
|
|
||||||
setArg(key, next, arg);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else if (/^(true|false)$/.test(next)) {
|
|
||||||
setArg(key, next === 'true', arg);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setArg(key, flags.strings[key] ? '' : true, arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (/^-[^-]+/.test(arg)) {
|
|
||||||
var letters = arg.slice(1,-1).split('');
|
|
||||||
|
|
||||||
var broken = false;
|
|
||||||
for (var j = 0; j < letters.length; j++) {
|
|
||||||
var next = arg.slice(j+2);
|
|
||||||
|
|
||||||
if (next === '-') {
|
|
||||||
setArg(letters[j], next, arg)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) {
|
|
||||||
setArg(letters[j], next.split('=')[1], arg);
|
|
||||||
broken = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/[A-Za-z]/.test(letters[j])
|
|
||||||
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
|
|
||||||
setArg(letters[j], next, arg);
|
|
||||||
broken = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (letters[j+1] && letters[j+1].match(/\W/)) {
|
|
||||||
setArg(letters[j], arg.slice(j+2), arg);
|
|
||||||
broken = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = arg.slice(-1)[0];
|
|
||||||
if (!broken && key !== '-') {
|
|
||||||
if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
|
|
||||||
&& !flags.bools[key]
|
|
||||||
&& (aliases[key] ? !aliasIsBoolean(key) : true)) {
|
|
||||||
setArg(key, args[i+1], arg);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else if (args[i+1] && /^(true|false)$/.test(args[i+1])) {
|
|
||||||
setArg(key, args[i+1] === 'true', arg);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setArg(key, flags.strings[key] ? '' : true, arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
|
|
||||||
argv._.push(
|
|
||||||
flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (opts.stopEarly) {
|
|
||||||
argv._.push.apply(argv._, args.slice(i + 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(defaults).forEach(function (key) {
|
|
||||||
if (!hasKey(argv, key.split('.'))) {
|
|
||||||
setKey(argv, key.split('.'), defaults[key]);
|
|
||||||
|
|
||||||
(aliases[key] || []).forEach(function (x) {
|
|
||||||
setKey(argv, x.split('.'), defaults[key]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (opts['--']) {
|
|
||||||
argv['--'] = new Array();
|
|
||||||
notFlags.forEach(function(key) {
|
|
||||||
argv['--'].push(key);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
notFlags.forEach(function(key) {
|
|
||||||
argv._.push(key);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return argv;
|
|
||||||
};
|
|
||||||
|
|
||||||
function hasKey (obj, keys) {
|
|
||||||
var o = obj;
|
|
||||||
keys.slice(0,-1).forEach(function (key) {
|
|
||||||
o = (o[key] || {});
|
|
||||||
});
|
|
||||||
|
|
||||||
var key = keys[keys.length - 1];
|
|
||||||
return key in o;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNumber (x) {
|
|
||||||
if (typeof x === 'number') return true;
|
|
||||||
if (/^0x[0-9a-f]+$/i.test(x)) return true;
|
|
||||||
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function isConstructorOrProto (obj, key) {
|
|
||||||
return key === 'constructor' && typeof obj[key] === 'function' || key === '__proto__';
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue