Skip to content

Commit 9d1907f

Browse files
authored
Merge pull request #14434 from NixOS/improve-ipv6-zoneid-backcompat
libstore: Improve store-reference back-compat with IPv6 ZoneId literals
2 parents c29411a + 8dbc247 commit 9d1907f

File tree

8 files changed

+92
-2
lines changed

8 files changed

+92
-2
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh://userinfo@[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%eth0]?a=b&c=d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh://userinfo@[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%25eth0]?a=b&c=d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh://userinfo@fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%25?a=b&c=d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh://userinfo@fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%eth0?a=b&c=d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh://fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%eth0?a=b&c=d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh://fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%eth0

src/libstore-tests/store-reference.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,64 @@ static StoreReference sshIPv6AuthorityWithUserinfoAndParams{
186186

187187
URI_TEST_READ(ssh_unbracketed_ipv6_3, sshIPv6AuthorityWithUserinfoAndParams)
188188

189+
static const StoreReference sshIPv6AuthorityWithUserinfoAndParamsAndZoneId{
190+
.variant =
191+
StoreReference::Specified{
192+
.scheme = "ssh",
193+
.authority = "userinfo@[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%25eth0]",
194+
},
195+
.params =
196+
{
197+
{"a", "b"},
198+
{"c", "d"},
199+
},
200+
};
201+
202+
URI_TEST_READ(ssh_unbracketed_ipv6_4, sshIPv6AuthorityWithUserinfoAndParamsAndZoneId)
203+
URI_TEST_READ(ssh_unbracketed_ipv6_5, sshIPv6AuthorityWithUserinfoAndParamsAndZoneId)
204+
205+
static const StoreReference sshIPv6AuthorityWithUserinfoAndParamsAndZoneIdTricky{
206+
.variant =
207+
StoreReference::Specified{
208+
.scheme = "ssh",
209+
.authority = "userinfo@[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%2525]",
210+
},
211+
.params =
212+
{
213+
{"a", "b"},
214+
{"c", "d"},
215+
},
216+
};
217+
218+
// Non-standard syntax where the IPv6 literal appears without brackets. In
219+
// this case don't considering %25 to be a pct-encoded % and just take it as a
220+
// literal value. 25 is a perfectly legal ZoneId value in theory.
221+
URI_TEST_READ(ssh_unbracketed_ipv6_6, sshIPv6AuthorityWithUserinfoAndParamsAndZoneIdTricky)
222+
URI_TEST_READ(ssh_unbracketed_ipv6_7, sshIPv6AuthorityWithUserinfoAndParamsAndZoneId)
223+
224+
static const StoreReference sshIPv6AuthorityWithParamsAndZoneId{
225+
.variant =
226+
StoreReference::Specified{
227+
.scheme = "ssh",
228+
.authority = "[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%25eth0]",
229+
},
230+
.params =
231+
{
232+
{"a", "b"},
233+
{"c", "d"},
234+
},
235+
};
236+
237+
URI_TEST_READ(ssh_unbracketed_ipv6_8, sshIPv6AuthorityWithParamsAndZoneId)
238+
239+
static const StoreReference sshIPv6AuthorityWithZoneId{
240+
.variant =
241+
StoreReference::Specified{
242+
.scheme = "ssh",
243+
.authority = "[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e%25eth0]",
244+
},
245+
};
246+
247+
URI_TEST_READ(ssh_unbracketed_ipv6_9, sshIPv6AuthorityWithZoneId)
248+
189249
} // namespace nix

src/libstore/store-reference.cc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,39 @@ StoreReference StoreReference::parse(const std::string & uri, const StoreReferen
121121
* greedily assumed to be the part of the host address. */
122122
auto authorityString = schemeAndAuthority->authority;
123123
auto userinfo = splitPrefixTo(authorityString, '@');
124-
auto maybeIpv6 = boost::urls::parse_ipv6_address(authorityString);
124+
/* Back-compat shim for ZoneId specifiers. Technically this isn't
125+
* standard, but the expectation is this works with the old syntax
126+
* for ZoneID specifiers. For the full story behind the fiasco that
127+
* is ZoneID in URLs look at [^].
128+
* [^]: https://datatracker.ietf.org/doc/html/draft-schinazi-httpbis-link-local-uri-bcp-03
129+
*/
130+
131+
/* Fish out the internals from inside square brackets. It might be that the pct-sign is unencoded and that's
132+
* why we failed to parse it previously. */
133+
if (authorityString.starts_with('[') && authorityString.ends_with(']')) {
134+
authorityString.remove_prefix(1);
135+
authorityString.remove_suffix(1);
136+
}
137+
138+
auto maybeBeforePct = splitPrefixTo(authorityString, '%');
139+
bool hasZoneId = maybeBeforePct.has_value();
140+
auto maybeZoneId = hasZoneId ? std::optional{authorityString} : std::nullopt;
141+
142+
std::string_view maybeIpv6S = maybeBeforePct.value_or(authorityString);
143+
auto maybeIpv6 = boost::urls::parse_ipv6_address(maybeIpv6S);
144+
125145
if (maybeIpv6) {
126146
std::string fixedAuthority;
127147
if (userinfo) {
128148
fixedAuthority += *userinfo;
129149
fixedAuthority += '@';
130150
}
131151
fixedAuthority += '[';
132-
fixedAuthority += authorityString;
152+
fixedAuthority += maybeIpv6S;
153+
if (maybeZoneId) {
154+
fixedAuthority += "%25"; // pct-encoded percent character
155+
fixedAuthority += *maybeZoneId;
156+
}
133157
fixedAuthority += ']';
134158
return {
135159
.variant =

0 commit comments

Comments
 (0)