• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package web
6
7import (
8	"errors"
9	"net/url"
10	"path/filepath"
11	"strings"
12)
13
14// TODO(golang.org/issue/32456): If accepted, move these functions into the
15// net/url package.
16
17var errNotAbsolute = errors.New("path is not absolute")
18
19func urlToFilePath(u *url.URL) (string, error) {
20	if u.Scheme != "file" {
21		return "", errors.New("non-file URL")
22	}
23
24	checkAbs := func(path string) (string, error) {
25		if !filepath.IsAbs(path) {
26			return "", errNotAbsolute
27		}
28		return path, nil
29	}
30
31	if u.Path == "" {
32		if u.Host != "" || u.Opaque == "" {
33			return "", errors.New("file URL missing path")
34		}
35		return checkAbs(filepath.FromSlash(u.Opaque))
36	}
37
38	path, err := convertFileURLPath(u.Host, u.Path)
39	if err != nil {
40		return path, err
41	}
42	return checkAbs(path)
43}
44
45func urlFromFilePath(path string) (*url.URL, error) {
46	if !filepath.IsAbs(path) {
47		return nil, errNotAbsolute
48	}
49
50	// If path has a Windows volume name, convert the volume to a host and prefix
51	// per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/.
52	if vol := filepath.VolumeName(path); vol != "" {
53		if strings.HasPrefix(vol, `\\`) {
54			path = filepath.ToSlash(path[2:])
55			i := strings.IndexByte(path, '/')
56
57			if i < 0 {
58				// A degenerate case.
59				// \\host.example.com (without a share name)
60				// becomes
61				// file://host.example.com/
62				return &url.URL{
63					Scheme: "file",
64					Host:   path,
65					Path:   "/",
66				}, nil
67			}
68
69			// \\host.example.com\Share\path\to\file
70			// becomes
71			// file://host.example.com/Share/path/to/file
72			return &url.URL{
73				Scheme: "file",
74				Host:   path[:i],
75				Path:   filepath.ToSlash(path[i:]),
76			}, nil
77		}
78
79		// C:\path\to\file
80		// becomes
81		// file:///C:/path/to/file
82		return &url.URL{
83			Scheme: "file",
84			Path:   "/" + filepath.ToSlash(path),
85		}, nil
86	}
87
88	// /path/to/file
89	// becomes
90	// file:///path/to/file
91	return &url.URL{
92		Scheme: "file",
93		Path:   filepath.ToSlash(path),
94	}, nil
95}
96