1// Copyright 2018 The Hugo Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package paths
15
16import (
17	"fmt"
18	"net/url"
19	"strings"
20)
21
22// A BaseURL in Hugo is normally on the form scheme://path, but the
23// form scheme: is also valid (mailto:hugo@rules.com).
24type BaseURL struct {
25	url    *url.URL
26	urlStr string
27}
28
29func (b BaseURL) String() string {
30	if b.urlStr != "" {
31		return b.urlStr
32	}
33	return b.url.String()
34}
35
36func (b BaseURL) Path() string {
37	return b.url.Path
38}
39
40// HostURL returns the URL to the host root without any path elements.
41func (b BaseURL) HostURL() string {
42	return strings.TrimSuffix(b.String(), b.Path())
43}
44
45// WithProtocol returns the BaseURL prefixed with the given protocol.
46// The Protocol is normally of the form "scheme://", i.e. "webcal://".
47func (b BaseURL) WithProtocol(protocol string) (string, error) {
48	u := b.URL()
49
50	scheme := protocol
51	isFullProtocol := strings.HasSuffix(scheme, "://")
52	isOpaqueProtocol := strings.HasSuffix(scheme, ":")
53
54	if isFullProtocol {
55		scheme = strings.TrimSuffix(scheme, "://")
56	} else if isOpaqueProtocol {
57		scheme = strings.TrimSuffix(scheme, ":")
58	}
59
60	u.Scheme = scheme
61
62	if isFullProtocol && u.Opaque != "" {
63		u.Opaque = "//" + u.Opaque
64	} else if isOpaqueProtocol && u.Opaque == "" {
65		return "", fmt.Errorf("cannot determine BaseURL for protocol %q", protocol)
66	}
67
68	return u.String(), nil
69}
70
71// URL returns a copy of the internal URL.
72// The copy can be safely used and modified.
73func (b BaseURL) URL() *url.URL {
74	c := *b.url
75	return &c
76}
77
78func newBaseURLFromString(b string) (BaseURL, error) {
79	var result BaseURL
80
81	base, err := url.Parse(b)
82	if err != nil {
83		return result, err
84	}
85
86	return BaseURL{url: base, urlStr: base.String()}, nil
87}
88