Parse anchor in remote URL

I've never seen this in practice, but if it does happen, we shouldn't
include it in the value for "path".
This commit is contained in:
Tim Pope
2022-02-11 11:36:03 -05:00
parent 6c19f1ddfb
commit c29ef11cd6

View File

@@ -1240,29 +1240,40 @@ endfunction
function! s:UrlParse(url) abort function! s:UrlParse(url) abort
let scp_authority = matchstr(a:url, '^[^:/]\+\ze:\%(//\)\@!') let scp_authority = matchstr(a:url, '^[^:/]\+\ze:\%(//\)\@!')
if len(scp_authority) && !(has('win32') && scp_authority =~# '^\a:[\/]') if len(scp_authority) && !(has('win32') && scp_authority =~# '^\a:[\/]')
let url = {'scheme': 'ssh', 'authority': scp_authority, let url = {'scheme': 'ssh', 'authority': scp_authority, 'hash': '',
\ 'path': strpart(a:url, len(scp_authority) + 1)} \ 'path': substitute(strpart(a:url, len(scp_authority) + 1), '[#?]', '\=printf("%%%02X", char2nr(submatch(0)))', 'g')}
elseif empty(a:url) elseif empty(a:url)
let url = {'scheme': '', 'authority': '', 'path': ''} let url = {'scheme': '', 'authority': '', 'path': '', 'hash': ''}
else else
let match = matchlist(a:url, '^\([[:alnum:].+-]\+\)://\([^/]*\)\(/.*\)\=\%(#\|$\)') let match = matchlist(a:url, '^\([[:alnum:].+-]\+\)://\([^/]*\)\(/[^#]*\)\=\(#.*\)\=$')
if empty(match) if empty(match)
let url = {'scheme': 'file', 'authority': '', 'path': a:url} let url = {'scheme': 'file', 'authority': '', 'hash': '',
\ 'path': substitute(a:url, '[#?]', '\=printf("%%%02X", char2nr(submatch(0)))', 'g')}
else else
let url = {'scheme': match[1], 'authority': match[2]} let url = {'scheme': match[1], 'authority': match[2], 'hash': match[4]}
let url.path = empty(match[3]) ? '/' : match[3] let url.path = empty(match[3]) ? '/' : match[3]
endif endif
endif endif
if (url.scheme ==# 'ssh' || url.scheme ==# 'git') && url.path[0:1] ==# '/~' if (url.scheme ==# 'ssh' || url.scheme ==# 'git') && url.path[0:1] ==# '/~'
let url.path = strpart(url.path, 1) let url.path = strpart(url.path, 1)
endif endif
if url.path =~# '^/'
let url.href = url.scheme . '://' . url.authority . url.path . url.hash
elseif url.path =~# '^\~'
let url.href = url.scheme . '://' . url.authority . '/' . url.path . url.hash
elseif url.scheme ==# 'ssh' && url.authority !~# ':'
let url.href = url.authority . ':' . url.path . url.hash
else
let url.href = a:url
endif
let url.url = matchstr(url.href, '^[^#]*')
return url return url
endfunction endfunction
function! s:RemoteResolve(url, flags) abort function! s:RemoteResolve(url, flags) abort
let remote = s:UrlParse(a:url) let remote = s:UrlParse(a:url)
if remote.scheme =~# '^https\=$' && index(a:flags, ':nohttp') < 0 if remote.scheme =~# '^https\=$' && index(a:flags, ':nohttp') < 0
let headers = fugitive#RemoteHttpHeaders(remote.scheme . '://' . remote.authority . remote.path) let headers = fugitive#RemoteHttpHeaders(remote.url)
let loc = matchstr(get(headers, 'location', ''), '^https\=://.\{-\}\ze/info/refs?') let loc = matchstr(get(headers, 'location', ''), '^https\=://.\{-\}\ze/info/refs?')
if len(loc) if len(loc)
let remote = s:UrlParse(loc) let remote = s:UrlParse(loc)
@@ -1312,15 +1323,6 @@ function! s:RemoteCallback(config, into, flags, cb) abort
let a:into.host = substitute(a:into.authority, '.\{-\}@', '', '') let a:into.host = substitute(a:into.authority, '.\{-\}@', '', '')
let a:into.hostname = substitute(a:into.host, ':\d\+$', '', '') let a:into.hostname = substitute(a:into.host, ':\d\+$', '', '')
let a:into.port = matchstr(a:into.host, ':\zs\d\+$', '', '') let a:into.port = matchstr(a:into.host, ':\zs\d\+$', '', '')
if a:into.path =~# '^/'
let a:into.url = a:into.scheme . '://' . a:into.authority . a:into.path
elseif a:into.path =~# '^\~'
let a:into.url = a:into.scheme . '://' . a:into.authority . '/' . a:into.path
elseif a:into.scheme ==# 'ssh' && a:into.authority !~# ':'
let a:into.url = a:into.authority . ':' . a:into.path
else
let a:into.url = url
endif
if len(a:cb) if len(a:cb)
call call(a:cb[0], [a:into] + a:cb[1:-1]) call call(a:cb[0], [a:into] + a:cb[1:-1])
endif endif