Git Product home page Git Product logo

url-polyfill's Introduction

Polyfill URL and URLSearchParams to match last WHATWG specifications

Compliant in most of the use cases but not at 100% (like unicode chars, punycodes, etc...)

Tested on IE 10+

Install

npm i url-polyfill --save

Currently supported

window.URL

Documentation: https://developer.mozilla.org/en-US/docs/Web/API/URL

Supported : 'hash', 'host', 'hostname', 'href', 'port', 'protocol', 'search', 'toString', 'pathname', 'origin', 'searchParams'

Example:

const url = new URL('https://www.example.com:8080/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0');
  • hash: "page0"
  • host: "www.example.com:8080"
  • hostname: "www.example.com"
  • href: "https://www.example.com:8080/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0"
  • origin: "https://www.example.com:8080"
  • pathname: "/"
  • port: "8080"
  • protocol: "https:"
  • search: "?fr=yset_ie_syc_oracle&type=orcl_hpset"
  • searchParams: URLSearchParams (see next)
window.URLSearchParams

Documentation: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

Supported : 'append', 'delete', 'get', 'getAll', 'has', 'set', 'forEach', 'keys', 'values', 'entries', 'toString', 'Symbol.iterator'

Example:

const url = new URL('https://www.example.com/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0');
url.searchParams.append('page', 0);
console.log(url.toString()); // print: "https://www.example.com/?fr=yset_ie_syc_oracle&type=orcl_hpset&page=0#page0"

url-polyfill's People

Contributors

acifani avatar andrejpavlovic avatar csvn avatar dukejeffrie avatar janicklas-ralph avatar janpot avatar kmashint avatar lifaon74 avatar moshest avatar raymondelooff avatar satinjeet avatar vcarl avatar zh99998 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

url-polyfill's Issues

"Invalid Argument" on "new URLSearchParams(formData.entries())" in Edge 44.18362.449.0

It seems url-polyfill is not detecting an incorrect behaviour from edge and therefore not polyfilling the whole URLSearchParams with standard behaviour. Even if I add the polyfill before the code, it falls back to edge behaviour which breaks the code, requiring custom browser workaround.

Failing code:

const formData = new FormData(event.target);
alert(new URLSearchParams([...formData.entries()]).toString());

SSCCE that fails on Edge and includes the polyfill in "resources": https://jsfiddle.net/v138s4x2/

If you use spread, it works. Here's my workaround at the moment:

const formData = new FormData(event.target);
alert(new URLSearchParams([...formData.entries()]).toString());

The reason is outlined here:

The problem in Edge is that they do not support destructuring of FormData object. (for ... of in linked table).

Expected behavior:

The polyfill detects and intercepts the faulty behavior from Edge and overrides URLSearchParams with standard behavior

【feature-umd bundle】 Support import instead of changing global objects

This project is very good, I like it too, thank you for your contribution.

I think that instead of changing the global environment, it is better to provide a bundle in UMD format, so that some projects that do not want to change the global environment can be introduced according to their own needs.

Error parsing invalid URL

Parsing http:/localhost/ with the native URL returns

{
  hash: "",
  host: "localhost",
  hostname: "localhost",
  href: "http://localhost/",
  origin: "http://localhost",
  password: "",
  pathname: "/",
  port: "",
  protocol: "http:",
  search: "",
  searchParams: {},
  username: ""
}

polyfill returns

{
  hash: "",
  host: "",
  hostname: "",
  href: "http://localhost/localhost/",
  origin: "http://",
  password: "",
  pathname: "/localhost/",
  port: "",
  protocol: "http:",
  search: "",
  searchParams: {},
  username: ""
}

IE11 Object doesn't support property or method '_fromString'

Hi, after update to 1.1.0, we are getting this error in IE11:

Object doesn't support property or method '_fromString'

in this peace of code:

this.searchParams._fromString(this.search);

Previous version of the polyfill worked fine.

I have no idea why this happens...

Also it would be nice to separate URL and URLSearchParams polyfills so we could use only one of them, and replace the other one with something else in cases like this.

Best regards!

Missing URLSearchParams#toString in url.ts and url.js

First of all, thank you for crafting a concise and excellent library. Our product runs into native code barfing with new URL in mobile Safari on iOS and I played around with your standalone classes and found them to be a perfect fit. Wondering if you have a public release planned with these classes soon.

const url = new URL('http://echo/')
url.searchParams.set('qux', 'baz')
console.log(url.toString())

....
http://echo/?[object Object]

FWIW, was able to resolve things trivially with the following port from url-polyfill.js:

URLSearchParams.prototype.toString = function () { 
  var pairs = []; 
  this.forEach(function (value, name) { 
    pairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(value)); 
  }); 
  return pairs.join('&'); 
}; 
toString() {
  const pairs = [];
  this.forEach(function (value, name) {
    pairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
  });
  return pairs.join('&');
}

Different behavior in IE and Chrome

I used this url-polyfill to validate the URL provided by the user and while testing in IE I realized that the behavior in IE and Google Chrom is completely different.

The function where I am using the url-polyfill is this:
image

The logs in Chrome is this (which is correct behavior for "sdfdsfdsf" provided as a URL):
image

The logs in IE is this (which is not expected for the "sdfdsfdsf" provided as a URL):
image

Version of IE: 11.0.9600.18860
Version of Chrome: 64.0.3282.186
Environment: VM - Windows 7 (32)

'base' argument is not stringified

The change from #61 adds a 'toLowerCase' call to the base variable. The code assumes that the value passed to the base argument is always a string. However, it's also possible to pass an existing URL object to both arguments. The values should both be stringified, but only the url argument is currently stringified.

Passing an URL object to the base argument results in the following error:

Object doesn't support property or method 'toLowerCase'

Fails when running in NodeJS.

Hi,

I am trying to use this api in NodeJS.
Fails because window is undefined inside NodeJS.
Should be able to attach this api to global.
Suggest removing window check.

Using nasty workaround to get it working:

const window: any = (global as any).window = global;
window.location = {};

With Kind Regards,
Albert Willemsen

TypeError: Cannot read property 'apply' of undefined

Got the following error:

TypeError: Cannot read property 'apply' of undefined
  apply (webpack:///node_modules/url-polyfill/url-polyfill.js:305:0),

Raised when calling url.searchParams.set(key, value);

User agents:

Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36

Polyfill for server

I used the url.js to polyfill URL and URLSearchParams on the server since it didn't use document. But that file is moved to do-not-use/url.js now. url-polyfill.js uses document in the constructor and basically just acts as a API on top of an DOM <a> so that doesn't work. Why shouldn't we use url.js?

Does not work in React Native (non-DOM scope)

I am trying to use this in a react native project. When I do:

import 'url-polyfill'

console.log('URL:', URL);
console.log('url:', new URL('http://www.google.com?inq=true&q=1#inh=true&h=1'));

It errors with:

document is not defined

Is it possible to use this in a non-DOM scope?

[IE] Port is resolved to 80 when unspecified

Input:

new URL('http://a.com')

Output:

{
  ...
  href: 'http://a.com/',
  origin: 'http://a.com:80',
  port: '80',
  ...
}

Expected (as is in Chrome):

{
  ...
  href: 'http://a.com/',
  origin: 'http://a.com',
  port: '',
  ...
}

Edit: this consequence seems to occur in IE only :/

Error parsing params values with =

= simbol is allowed as a url param value.

Example:
new UrlSearchParams('?param1=valuewith=&param2=bar');

This example breaks un the unexpected value: {param1: valuewith , param2: bar}

expected: {param1: valuewith= , param2: bar}

ReferenceError: document is not defined (in node)

Just curious - is this meant to work in node? I was hoping it would so I can run unit tests there without mocking out the URL/URLSearchParams APIs. This is the error:

$ cat test.js
require('url-polyfill')
u = new URL('https://example.com/')
$ node test.js
/Users/jrz/node_modules/url-polyfill/url-polyfill.js:174
      var doc = document.implementation.createHTMLDocument('');
                                        ^

ReferenceError: document is not defined
    at new URL (/Users/jrz/node_modules/url-polyfill/url-polyfill.js:174:41)
    at Object.<anonymous> (/Users/jrz/test.js:3:5)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:383:7)
    at startup (bootstrap_node.js:149:9)
$ node -v
v6.12.0

URLSearchParams and URL referenced globally instead of as properties of 'global' parameter

if (!('URLSearchParams' in global) || (new URLSearchParams('?a=1').toString() !== 'a=1')) {
polyfillURLSearchParams();
}

Since we are checking if URLSearchParams is present in the global variable, we should also then instantiate URLSearchParams from the global variable. So instead of new URLSearchParams it should be new global.new URLSearchParams, since URLSearchParams is not necessarily the same as global.URLSearchParams.

Fix:

 if (!('URLSearchParams' in global) || (new global.URLSearchParams('?a=1').toString() !== 'a=1')) { 
   polyfillURLSearchParams(); 
 } 

reuse searchParams

currently every time get searchParams will create a new object, which is waste memory and cause problem.
currently, in chrome 49.

const url = new URL('http://example.com/?a=1');
url.searchParams.set('b','2')
url.searchParams.set('c','3')
console.log(url.toString())

=>

http://example.com/?%3F%3Fa=1&b=2&c=3

will get some mysterious %3F in search string, seems it's caused by duplicated searchParams create.


btw, chrome 49 support both URL and URLSearchParams, but no url.searchParams.
this may help you debug.


well no i guess wrong.
only one searchParams call will cause this problem too.

const url = new URL('http://example.com/?a=1');
const params = url.searchParams;
params.set('b','2');
params.set('c','3');
console.log(url.toString())

=>

http://example.com/?%3Fa=1&b=2&c=3

I found that.

this version of chrome native URLSearchParams doesn't cut leading ?

in chrome 49

new URLSearchParams('?a=1').toString() #=> "%3Fa=1"

in chrome 60

new URLSearchParams('?a=1').toString() #=> "a=1"

seems these should be more check before using native URLSearchParams, like

  if(!('URLSearchParams' in global && new URLSearchParams('?a=1').toString() === 'a=1')) {
    polyfillURLSearchParams();
  }

URLSearchParams divergence from Firefox & Chrome

Seems the URLSearchParams implentation is not consistent with the Firefox and Chrome behavior.

Using Chrome 63 and Firefox 57:

let url = new URL('https://www.example.com/?key=hello+world');
url.searchParams.get('key');

The result is: "hello world"

Using the polyfill and the same code in Edge 16, the result is:
"hello+world"

Tag releases

Thanks for this project! I see versions have been "released" in the package.json file, but I'm wondering if you could also tag the releases in GitHub?

URL constructor does not accept objects. The browsers that implement the spec do.

If passing an object to the URL constructor, in Firefox and Chrome it will use the toString() property of the object as the URL to process. This is most obvious (and useful) when passing a Location object such as window.location.
The polyfill does not do this; it simply checks if the parameter is typeof string, and if not it throws an exception.

Line 173 of url-polyfill.js should be either removed or accept objects and call their toString() method.
Before the line
if(typeof url !== 'string') throw new TypeError('Failed to construct \'URL\': Invalid URL');
we can add
if (typeof url === 'object') url = url.toString();
which will solve the problem

Polyfill broken in V1.1.X

This polyfill is broken for e.g. Safari 10 since Version 1.1.X.
Please fix this!

JS error from console:

this.searchParams._fromString is not a function.

Should preserve the same URL if no params to delete

I found a small inconsistency with native Chrome implementation when trying to delete search param.

Here is the test case:

// OK
it('should preserve the same string if no param to delete', function () {
  let url = new URL('https://www.example.com/?bar=1');
  url.searchParams.delete('foo');
  expect(url.toString()).to.equal('https://www.example.com/?bar=1');
});

// expected 'https://www.example.com/?' to equal 'https://www.example.com/'
it('should preserve the same string if no any params to delete', function () {
  let url = new URL('https://www.example.com/');
  url.searchParams.delete('foo');
  expect(url.toString()).to.equal('https://www.example.com/');
});

It adds an extra ? if no params present.

Inconsistent when double '?' in string

In Chrome 63, If I run:

const test1 = new URLSearchParams('?a=1?b=2&c=3');
test1.get('a');

then I get 1?b=2

With this polyfill, I get 1?b.

Url-search-params-polyfill also mimicks the Chrome behavior.

Spaces are encoded differently with the polyfill

When using a form submit to search, forms encode spaces as +:

<form action="/search">
  <input type="hidden" name="q" value="hello world">
</form>
<!-- Submit results in URL: "<origin>/search?q=hello+world" -->

When decoding this URL and fetching the q parameter the result differs between browsers with and without polyfill:

// href => <origin>/search?q=hello+world
const url = new URL(location.href);
console.log(url.searchParams.get('q'));
// Prints "hello world" in latest Chrome
// Prints "hello+world" in Edge with this polyfill

I looked up how parameters with URLSearchParams should be handled, and it seems the search params should use form encoding:

  1. Set should update entry list, and then do the update steps (whatwg)
  2. The update steps should serialize all search params (whatwg)
  3. Serialization uses the form encode serializer (whatwg)
  4. The serialization above uses a byte serializer where spaces should be replaced by + for both search param name and values (whatwg)

In short, the steps for encoding that are listed on whatwg seems to follow encodeURIComponent() except for + which is encoded as %20. I suggest that a method that respects space as + to be followed for decoding and encoding search params and their values.

searchParams should be two way bound

  1. URLSearchParams MUST be reused (like in #9)
  2. modification of url.search MUST modify searchParams

Example:

const u = new URL('http://example.org/?')
const sp = u.searchParams
console.log(sp === u.searchParams);

u.search = "x=1"
console.log(sp.get('x'))


sp.set('y', 1)

console.log(u.search)
sp.set('y', null);
console.log('' + sp)

Look at screenshot (left - native URL, right - polyfill)

image

IE11 object missing most fields

Here's my example URL:
https://dash.local/Auth/o/authorize/?response_type=token&client_id=eC5Tuezee6eebahn5xo9moo4edai2weepheethah&redirect_uri=https://dash.local/Manager/oauth2-redirect&state=Manager

When I parse it in Chrome:

hash: ""
host: "dash.local"
hostname: "dash.local"
href: "https://dash.local/Auth/o/authorize/?response_type=token&client_id=eC5Tuezee6eebahn5xo9moo4edai2weepheethah&redirect_uri=https://dash.local/Manager/oauth2-redirect&state=Manager"
origin: "https://dash.local"
password: ""
pathname: "/Auth/o/authorize/"
port: ""
protocol: "https:"
search: "?response_type=token&client_id=eC5Tuezee6eebahn5xo9moo4edai2weepheethah&redirect_uri=https://dash.local/Manager/oauth2-redirect&state=Manager"
searchParams: URLSearchParams {}
username: ""
__proto__: URL

When I parse it in IE11 (that thing won't let me copy/paste...):

image

host, hostname, protocol are all missing.

not working in nativescript

Probably not an intended target environment, but trying to instantiate a URL in nativescript results in an exception: ReferenceError: document is not defined.

Empty URL properties when using base-URL

The baseURL-parameter passed to the constructor seems to be ignored when calculating the property values (e.g. origin) of the resulting URL object.

Two screenshots from the IE11 console to illustrate the problem

The first one shows the correct result, when creating an URL object without using a base-URL:

ie11 url - without baseurl

The second shows the empty properties when the same URL is created of from a base-URL:

ie11 url - with baseurl

Construction using window.location.href as base throws Invalid URL

When attempting to construct a URL using a relative path and a base argument matching the current document's window.location.href, an error TypeError: Invalid URL is thrown.

Environment: IE10
Steps to reproduce:

new URL("/my/path", window.location.href)

(in my test my path was http://timelord.local:4200/candidates;location=martin_pl;date=2019-12-24)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.