fastify/fast-uri

Relative paths don't survive serialize/parse

epoberezkin opened this issue · 3 comments

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

N/A

Plugin version

No response

Node.js version

16.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

Mac

Description

Not sure it's a bug - is it intended? uri-js, annoyingly, does the same...

Steps to Reproduce

const uri = require('fast-uri')
let parsed = uri.parse('../one/two.three?q1=a1&q2=a2#body')
console.log(parsed)
console.log(uri.serialize(parsed))

// Output:
// {
// scheme : "uri",
// userinfo : "user:pass",
// host : "example.com",
// port : 123,
// path : "../one/two.three",
// query : "q1=a1&q2=a2",
// fragment : "body"
// }
//
// "one/two.three?q1=a1&q2=a2#body"

https://runkit.com/esp/6319bd9f5b03ac0008add460

Expected Behavior

No response

zekth commented
const uri = require('fast-uri')
const urijs = require('uri-js')
let parsed = uri.parse('../one/two.three?q1=a1&q2=a2#body')
console.log(parsed)
console.log(uri.serialize(parsed))

parsed = urijs.parse('../one/two.three?q1=a1&q2=a2#body')
console.log(parsed)
console.log(urijs.serialize(parsed))
{
  scheme: undefined,       
  userinfo: undefined,     
  host: undefined,
  port: undefined,
  path: '../one/two.three',
  query: 'q1=a1&q2=a2',    
  fragment: 'body',        
  reference: 'relative'    
}
one/two.three?q1=a1&q2=a2#body
{
  scheme: undefined,
  userinfo: undefined,
  host: undefined,
  port: undefined,
  path: '../one/two.three',
  query: 'q1=a1&q2=a2',
  fragment: 'body',
  reference: 'relative'
}
one/two.three?q1=a1&q2=a2#body

It's same as old behaviour, but indeed it looks like a bug to me

Eomm commented

Doesn't it relate to this issue garycourt/uri-js#31?

However, unlike in a file
system, these dot-segments are only interpreted within the URI path
hierarchy and are removed as part of the resolution process (Section
5.2).

https://www.ietf.org/rfc/rfc3986.txt

zekth commented

@epoberezkin just tried testing this and in fact with the absolutePath option it works. See:

'use strict'

const tap = require('tap')
const test = tap.test
const uri = require('../')

test('keep relative', (t) => {
    const inputs = [
        '../one/../two.three?q1=a1&q2=a2#body',
        '../one/two.three?q1=a1&q2=a2#body',
        '../../one/two.three?q1=a1&q2=a2#body',
    ]
    inputs.forEach((input) => {
        let parsed = uri.parse(input)
        t.same(uri.serialize(parsed, { absolutePath: true }), input, 'relative paths should be keeped')
    })
    t.end()
})

Does that fit your needs?