1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::parse::{MAX_PACKAGE_PATH_SEGMENT_BYTES, MAX_RESOURCE_PATH_SEGMENT_BYTES};
use thiserror::Error;

#[derive(PartialEq, Debug, Error)]
pub enum ParseError {
    #[error("missing scheme")]
    MissingScheme,

    #[error("invalid scheme")]
    InvalidScheme,

    #[error("cannot have a scheme")]
    CannotContainScheme,

    #[error("invalid host")]
    InvalidHost,

    #[error("empty host")]
    EmptyHost,

    #[error("missing host")]
    MissingHost,

    #[error("host must be empty to imply absolute path")]
    HostMustBeEmpty,

    #[error("invalid path segment")]
    InvalidPathSegment(#[source] PackagePathSegmentError),

    #[error("invalid name")]
    InvalidName(#[source] PackagePathSegmentError),

    #[error("URL path must start with '/'")]
    PathMustHaveLeadingSlash,

    #[error("missing name")]
    MissingName,

    #[error("invalid variant")]
    InvalidVariant(#[source] PackagePathSegmentError),

    #[error("missing hash")]
    MissingHash,

    #[error("missing resource")]
    MissingResource,

    #[error("invalid hash")]
    InvalidHash(#[source] fuchsia_hash::ParseHashError),

    #[error("uppercase hex characters in hash")]
    UpperCaseHash,

    #[error("multiple hash query parameters")]
    MultipleHashes,

    #[error("cannot contain hash")]
    CannotContainHash,

    #[error("path must be root")]
    PathMustBeRoot,

    #[error("resource path failed to percent decode")]
    ResourcePathPercentDecode(#[source] std::str::Utf8Error),

    #[error("invalid resource path")]
    InvalidResourcePath(#[source] ResourcePathError),

    #[error("cannot contain a resource path (a URL fragment)")]
    CannotContainResource,

    #[error("extra path segments")]
    ExtraPathSegments,

    #[error("extra query parameters")]
    ExtraQueryParameters,

    #[error("cannot contain port")]
    CannotContainPort,

    #[error("cannot contain username")]
    CannotContainUsername,

    #[error("cannot contain password")]
    CannotContainPassword,

    #[error("cannot contain query parameters")]
    CannotContainQueryParameters,

    #[error("relative path URL cannot specify a package hash")]
    RelativePathCannotSpecifyHash,

    #[error("relative path URL cannot specify a variant")]
    RelativePathCannotSpecifyVariant,

    #[error("relative URL could not be parsed into a relative package path, Some({0:?}) != {1:?}")]
    InvalidRelativePath(String, Option<String>),

    #[error(
        "relative URL with absolute path is not supported (relative path cannot start with `/`)"
    )]
    AbsolutePathNotSupported,

    #[error("invalid repository URI")]
    InvalidRepository,

    #[error("url parse error")]
    UrlParseError(#[from] url::ParseError),
}

#[derive(PartialEq, Eq, Debug, Error)]
pub enum PackagePathSegmentError {
    #[error("empty segment")]
    Empty,

    #[error(
        "segment too long. should be at most {} bytes, was {0} bytes",
        MAX_PACKAGE_PATH_SEGMENT_BYTES
    )]
    TooLong(usize),

    #[error("package path segments must consist of only digits (0 to 9), lower-case letters (a to z), hyphen (-), underscore (_), and period (.). this contained {character:?}")]
    InvalidCharacter { character: char },

    #[error("package path segments cannot be a single period")]
    DotSegment,

    #[error("package path segments cannot be two periods")]
    DotDotSegment,
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum ResourcePathError {
    #[error("object names must be at least 1 byte")]
    NameEmpty,

    #[error("object names must be at most {} bytes", MAX_RESOURCE_PATH_SEGMENT_BYTES)]
    NameTooLong,

    #[error("object names cannot contain the NULL byte")]
    NameContainsNull,

    #[error("object names cannot be '.'")]
    NameIsDot,

    #[error("object names cannot be '..'")]
    NameIsDotDot,

    #[error("object paths cannot start with '/'")]
    PathStartsWithSlash,

    #[error("object paths cannot end with '/'")]
    PathEndsWithSlash,

    #[error("object paths must be at least 1 byte")]
    PathIsEmpty,

    // TODO(https://fxbug.dev/42096516) allow newline once meta/contents supports it in blob paths
    #[error(r"object names cannot contain the newline character '\n'")]
    NameContainsNewline,
}