为什么 "/a" 是有效路径而 "/" 是无效路径?

14

我正在尝试理解为什么某些HTML属性无法通过W3C验证。我在一个真实的代码库中遇到了这个问题,但这里是一个最小化的复制版本:

<!DOCTYPE html><html lang="en"><head><title>a</title></head><body>

<img alt="1" src="⭐">
<img alt="2" src="/⭐">
<img alt="3" src="/a⭐">
<img alt="4" src="/a/⭐">
<img alt="5" src="">
<img alt="6" src="/"> <!-- Only this is invalid. -->
<img alt="7" src="/a">
<img alt="8" src="/a/">

</body></html>

W3C验证器仅报告一个错误,影响第六张图片:

  1. Error: Bad value / for attribute src on element img: Illegal character in path segment: ? is not allowed.

    <img alt="6" src="/">
    
为什么只有那一个是问题,而其他的不是?它有什么不同之处?

5
你可以通过他们的GitHub提交这个可能是bug的内容:https://github.com/validator/validator/issues - Heretic Monkey
3
顺便说一下,如果我发现代码中有一个错误,尤其是那些意图完全符合相关规范但实际上并没有符合的部分,我就会停下正在做的其他事情并致力于修复它——通常情况下,在我第一次发现这个漏洞的几个小时内就能解决。几个小时前,我只是无意中看到了这个SO的问题。因此,如果你在检查器中遇到其他可能是错误的问题,请像这里的其他人建议的那样,在https://github.com/validator/validator/issues上提出问题。 - sideshowbarker
3
此外,如果你在 Stack Overflow 上发布其他与检查器行为相关的问题,请标记为 [tag:w3c-validation] 标签。我会关注这个标签,每当有人发布问题时,我会在 15 分钟内得到通知(目前还有其他 77 个人关注此标签)。如果涉及 URL 的有效性且你不确定预期的行为应该是什么,可以在 https://matrix.to/#/#whatwg:matrix.org 的 WHATWG Matrix 房间中提问。对于 URL 相关的问题,使用 [tag:url-parsing] 标签会很有帮助。 - sideshowbarker
3
@ sideshowbarker 这个问题已经有 [tag:w3c-validation] 标签了,我不确定为什么 @TylerH 移除了它 - 可能是因为他认为这不是一个官方的 w3c 项目。 - Bergi
2
@TylerH,这个标签没有什么不好的,它显然是有用的。而且,这个问题不是关于任意验证的,而是关于w3c验证服务的,这些服务检查某些内容是否符合w3c标准。在再次删除标签之前,请将此讨论带到元数据中。 - Bergi
显示剩余4条评论
1个回答

13
问题描述中的行为是由检查器(验证程序)代码中的一个错误引起的,现已修复,请参见https://github.com/validator/galimatias/pull/2。由于测试套件没有涵盖以斜杠开头且代码点大于U+FFFF的相对URL的情况,例如问题中的U+1F30(彩虹)字符,因此这个bug被忽略了。因此,测试套件也被更新以覆盖该情况,请参见https://github.com/web-platform-tests/wpt/pull/36213

顺便提一下,U+2b50 (⭐) 未受到错误影响的原因是:Java使用UTF-16,而U+1F308位于所谓的补充字符范围内(即,代码点集在U+FFFF以上),因此 - 如上面的评论中所述 - 在UTF-16中,代码点U+1F308由两个代理对char值表示,而U+2b50则由单个char值表示。

而导致不同的char数量会影响URL解析方式的原因是,在HTML检查器的URL解析代码中,状态机维护一个字符索引,并在状态改变时递减它。因此,如果正在处理可以包含U+FFFF以上代码点的URL段,它必须聪明地知道要将索引递减多少个字符 - 对于U+FFFF以上的代码点,它需要将其减少2个字符,否则只需减少1个字符。

为了实现这一点,代码有一个 decrIdx() 方法,该方法调用 Character.charCount() 方法:

确定表示指定字符(Unicode 代码点)所需的 char 值的数量。如果指定的字符等于或大于 0x10000,则该方法返回 2。否则,该方法返回 1。

因此,对检查器进行的 代码更改 将索引值的简单递减 idx-- 替换为更聪明的 Character.charCount() 启用的 decrIdx() 调用。

“Java使用UTF-16”对我来说是最重要的一环。我已经阅读了状态机,但无法理解它在UTF-8中是如何工作的。 - ændrük

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接