├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json ├── redos.js └── test.js /.npmignore: -------------------------------------------------------------------------------- 1 | .travis.yml 2 | redos.js 3 | test.js -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | - "0.11" 5 | - "0.10" 6 | - "0.10.12" 7 | - "0.8" 8 | - "0.6" 9 | - "iojs" 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Javier Blanco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # path-parse [![Build Status](https://travis-ci.org/jbgutierrez/path-parse.svg?branch=master)](https://travis-ci.org/jbgutierrez/path-parse) 2 | 3 | > Node.js [`path.parse(pathString)`](https://nodejs.org/api/path.html#path_path_parse_pathstring) [ponyfill](https://ponyfill.com). 4 | 5 | ## Install 6 | 7 | ``` 8 | $ npm install --save path-parse 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```js 14 | var pathParse = require('path-parse'); 15 | 16 | pathParse('/home/user/dir/file.txt'); 17 | //=> { 18 | // root : "/", 19 | // dir : "/home/user/dir", 20 | // base : "file.txt", 21 | // ext : ".txt", 22 | // name : "file" 23 | // } 24 | ``` 25 | 26 | ## API 27 | 28 | See [`path.parse(pathString)`](https://nodejs.org/api/path.html#path_path_parse_pathstring) docs. 29 | 30 | ### pathParse(path) 31 | 32 | ### pathParse.posix(path) 33 | 34 | The Posix specific version. 35 | 36 | ### pathParse.win32(path) 37 | 38 | The Windows specific version. 39 | 40 | ## License 41 | 42 | MIT © [Javier Blanco](http://jbgutierrez.info) 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var isWindows = process.platform === 'win32'; 4 | 5 | // Regex to split a windows path into into [dir, root, basename, name, ext] 6 | var splitWindowsRe = 7 | /^(((?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?[\\\/]?)(?:[^\\\/]*[\\\/])*)((\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))[\\\/]*$/; 8 | 9 | var win32 = {}; 10 | 11 | function win32SplitPath(filename) { 12 | return splitWindowsRe.exec(filename).slice(1); 13 | } 14 | 15 | win32.parse = function(pathString) { 16 | if (typeof pathString !== 'string') { 17 | throw new TypeError( 18 | "Parameter 'pathString' must be a string, not " + typeof pathString 19 | ); 20 | } 21 | var allParts = win32SplitPath(pathString); 22 | if (!allParts || allParts.length !== 5) { 23 | throw new TypeError("Invalid path '" + pathString + "'"); 24 | } 25 | return { 26 | root: allParts[1], 27 | dir: allParts[0] === allParts[1] ? allParts[0] : allParts[0].slice(0, -1), 28 | base: allParts[2], 29 | ext: allParts[4], 30 | name: allParts[3] 31 | }; 32 | }; 33 | 34 | 35 | 36 | // Split a filename into [dir, root, basename, name, ext], unix version 37 | // 'root' is just a slash, or nothing. 38 | var splitPathRe = 39 | /^((\/?)(?:[^\/]*\/)*)((\.{1,2}|[^\/]+?|)(\.[^.\/]*|))[\/]*$/; 40 | var posix = {}; 41 | 42 | 43 | function posixSplitPath(filename) { 44 | return splitPathRe.exec(filename).slice(1); 45 | } 46 | 47 | 48 | posix.parse = function(pathString) { 49 | if (typeof pathString !== 'string') { 50 | throw new TypeError( 51 | "Parameter 'pathString' must be a string, not " + typeof pathString 52 | ); 53 | } 54 | var allParts = posixSplitPath(pathString); 55 | if (!allParts || allParts.length !== 5) { 56 | throw new TypeError("Invalid path '" + pathString + "'"); 57 | } 58 | 59 | return { 60 | root: allParts[1], 61 | dir: allParts[0].slice(0, -1), 62 | base: allParts[2], 63 | ext: allParts[4], 64 | name: allParts[3], 65 | }; 66 | }; 67 | 68 | 69 | if (isWindows) 70 | module.exports = win32.parse; 71 | else /* posix */ 72 | module.exports = posix.parse; 73 | 74 | module.exports.posix = posix.parse; 75 | module.exports.win32 = win32.parse; 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "path-parse", 3 | "version": "1.0.7", 4 | "description": "Node.js path.parse() ponyfill", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/jbgutierrez/path-parse.git" 12 | }, 13 | "keywords": [ 14 | "path", 15 | "paths", 16 | "file", 17 | "dir", 18 | "parse", 19 | "built-in", 20 | "util", 21 | "utils", 22 | "core", 23 | "ponyfill", 24 | "polyfill", 25 | "shim" 26 | ], 27 | "author": "Javier Blanco ", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/jbgutierrez/path-parse/issues" 31 | }, 32 | "homepage": "https://github.com/jbgutierrez/path-parse#readme" 33 | } 34 | -------------------------------------------------------------------------------- /redos.js: -------------------------------------------------------------------------------- 1 | var pathParse = require('.'); 2 | 3 | function build_attack(n) { 4 | var ret = "" 5 | for (var i = 0; i < n; i++) { 6 | ret += "/" 7 | } 8 | return ret + "◎"; 9 | } 10 | 11 | for(var i = 1; i <= 5000000; i++) { 12 | if (i % 10000 == 0) { 13 | var time = Date.now(); 14 | var attack_str = build_attack(i) 15 | pathParse.posix(attack_str); 16 | pathParse.win32(attack_str); 17 | var time_cost = Date.now() - time; 18 | console.log("attack_str.length: " + attack_str.length + ": " + time_cost+" ms") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var pathParse = require('./index'); 3 | 4 | var winParseTests = [ 5 | [{ root: 'C:\\', dir: 'C:\\path\\dir', base: 'index.html', ext: '.html', name: 'index' }, 'C:\\path\\dir\\index.html'], 6 | [{ root: 'C:\\', dir: 'C:\\another_path\\DIR\\1\\2\\33', base: 'index', ext: '', name: 'index' }, 'C:\\another_path\\DIR\\1\\2\\33\\index'], 7 | [{ root: '', dir: 'another_path\\DIR with spaces\\1\\2\\33', base: 'index', ext: '', name: 'index' }, 'another_path\\DIR with spaces\\1\\2\\33\\index'], 8 | [{ root: '\\', dir: '\\foo', base: 'C:', ext: '', name: 'C:' }, '\\foo\\C:'], 9 | [{ root: '', dir: '', base: 'file', ext: '', name: 'file' }, 'file'], 10 | [{ root: '', dir: '.', base: 'file', ext: '', name: 'file' }, '.\\file'], 11 | 12 | // unc 13 | [{ root: '\\\\server\\share\\', dir: '\\\\server\\share\\', base: 'file_path', ext: '', name: 'file_path' }, '\\\\server\\share\\file_path'], 14 | [{ root: '\\\\server two\\shared folder\\', dir: '\\\\server two\\shared folder\\', base: 'file path.zip', ext: '.zip', name: 'file path' }, '\\\\server two\\shared folder\\file path.zip'], 15 | [{ root: '\\\\teela\\admin$\\', dir: '\\\\teela\\admin$\\', base: 'system32', ext: '', name: 'system32' }, '\\\\teela\\admin$\\system32'], 16 | [{ root: '\\\\?\\UNC\\', dir: '\\\\?\\UNC\\server', base: 'share', ext: '', name: 'share' }, '\\\\?\\UNC\\server\\share'] 17 | ]; 18 | 19 | var winSpecialCaseFormatTests = [ 20 | [{dir: 'some\\dir'}, 'some\\dir\\'], 21 | [{base: 'index.html'}, 'index.html'], 22 | [{}, ''] 23 | ]; 24 | 25 | var unixParseTests = [ 26 | [{ root: '/', dir: '/home/user/dir', base: 'file.txt', ext: '.txt', name: 'file' }, '/home/user/dir/file.txt'], 27 | [{ root: '/', dir: '/home/user/a dir', base: 'another File.zip', ext: '.zip', name: 'another File' }, '/home/user/a dir/another File.zip'], 28 | [{ root: '/', dir: '/home/user/a dir/', base: 'another&File.', ext: '.', name: 'another&File' }, '/home/user/a dir//another&File.'], 29 | [{ root: '/', dir: '/home/user/a$$$dir/', base: 'another File.zip', ext: '.zip', name: 'another File' }, '/home/user/a$$$dir//another File.zip'], 30 | [{ root: '', dir: 'user/dir', base: 'another File.zip', ext: '.zip', name: 'another File' }, 'user/dir/another File.zip'], 31 | [{ root: '', dir: '', base: 'file', ext: '', name: 'file' }, 'file'], 32 | [{ root: '', dir: '', base: '.\\file', ext: '', name: '.\\file' }, '.\\file'], 33 | [{ root: '', dir: '.', base: 'file', ext: '', name: 'file' }, './file'], 34 | [{ root: '', dir: '', base: 'C:\\foo', ext: '', name: 'C:\\foo' }, 'C:\\foo'] 35 | ]; 36 | 37 | var unixSpecialCaseFormatTests = [ 38 | [{dir: 'some/dir'}, 'some/dir/'], 39 | [{base: 'index.html'}, 'index.html'], 40 | [{}, ''] 41 | ]; 42 | 43 | var errors = [ 44 | {input: null, message: /Parameter 'pathString' must be a string, not/}, 45 | {input: {}, message: /Parameter 'pathString' must be a string, not object/}, 46 | {input: true, message: /Parameter 'pathString' must be a string, not boolean/}, 47 | {input: 1, message: /Parameter 'pathString' must be a string, not number/}, 48 | {input: undefined, message: /Parameter 'pathString' must be a string, not undefined/}, 49 | ]; 50 | 51 | checkParseFormat(pathParse.win32, winParseTests); 52 | checkParseFormat(pathParse.posix, unixParseTests); 53 | checkErrors(pathParse.win32); 54 | checkErrors(pathParse.posix); 55 | 56 | function checkErrors(parse) { 57 | errors.forEach(function(errorCase) { 58 | try { 59 | parse(errorCase.input); 60 | } catch(err) { 61 | assert.ok(err instanceof TypeError); 62 | assert.ok( 63 | errorCase.message.test(err.message), 64 | 'expected ' + errorCase.message + ' to match ' + err.message 65 | ); 66 | return; 67 | } 68 | 69 | assert.fail('should have thrown'); 70 | }); 71 | } 72 | 73 | function checkParseFormat(parse, testCases) { 74 | testCases.forEach(function(testCase) { 75 | assert.deepEqual(parse(testCase[1]), testCase[0]); 76 | }); 77 | } 78 | --------------------------------------------------------------------------------