探索URL中~符号的起源
本文完整阅读约需 13 分钟,如时间较长请考虑收藏后慢慢阅读~
在很多高校、组织、机构的网站里,我们经常会看到形如
http://example.com/~john/index.html
的URL,其中的~
符号异常显眼,但介于主流搜索引擎总是屏蔽特殊符号,且国内使用该URL规则的网站少之又少,想要搜索其源头异常困难。
0x01
在这里抛出两个示例URL:
http://math.ecnu.edu.cn/~jypan/Teaching/NA/
https://www.cs.vu.nl/~ast/brown/
可以发现,这两个URL都存在以下共性:
– 第一级目录以~
符号开头
– 第一级目录除开~
符号以外,是该主页作者的用户名或用户名缩写
这样的规律不禁令人猜测,这一目录结构是否有其特殊原因?
0x02
『波浪线』这一词汇,在英文中有着多种表示,此处最恰当的应该是tilde
。
于是我在Google中搜索tilde in url
,得到了以下结果:
排行第一的链接中最高票回答揭解释了这一符号的用途:可用于定位用户的home目录。
尽管答主并未直接说明这一符号在URL中的由来,但我却突然被点醒,这又是一个与操作系统深度耦合的应用。
0x03
为什么我要说又,又为什么要说与操作系统深度耦合呢?
我先来卖个关子,拿Samba这个Linux下久负盛名的软件来说明。
Samba的配置过程中有两个很有意思的点:
- 默认配置下,每个用户都可以用自己的Linux用户名与密码登录到自己的home目录
- 如果需要设置一个共享目录,需新开一个用户,并将对应目录chown到该用户及其用户组上
这两点就是应用程序与操作系统深度耦合的一大典型。诸如此类的软件还有LDAP、FTP等。
我们在这里先不论深度耦合的正确与否,但这的确就是UNIX哲学的最大体现(即程序只做程序本身的事情,将用户管理的部分交给专门负责用户管理的模块负责),尤其是在『多用户』共享计算机资源当道的20世纪末期(现在的多用户其实已经成为了一个伪需求,大部分情况下计算机只有同时一个用户使用,其他的所谓『用户』执行者事实上都不是人,而是为了限制进程访问而作出的人为区分)。
而UNIX哲学的另一体现,则是早期的WebServer对目录的组织结构及其映射规则。
0x04
Apache甚至更早的WebServer都有一个配置叫做PerUser Directory
,理解过来就是『如果我需要在这台服务器上跑一个网页,我不需要和网站管理员额外申请,只需要放文件在我的用户目录下就可以被访问到』,而上文所提到的~xxx
就是这一特性的体现。
以Apache的配置为例:
- 首先我们需要引入相关配置:
Include conf/extra/httpd-userdir.conf
- 然后我们配置所有用户的Web目录:
UserDir public_html
配置结束后,通过诸如 https://example.com/~username/index.html 的方式就可以访问到public_html
目录里的静态资源,也就实现了网站的搭设。
- 如果我们想更专业一些,再来一点Retro Style,我们还可以加入cgi-bin的执行配置:
<Directory "/home/*/public_html/cgi-bin/">
Options ExecCGI
SetHandler cgi-script
</Directory>
这样就可以通过诸如 https://example.com/~username/cgi-bin/index.pl 的方式访问到服务器中属于该用户的可执行脚本
以上配置均可以在Apache最新的官方文档中找到,不免让人感叹历史的有趣之处,也让人感叹成功的软件总是在兼容性方面给人惊喜。
0x05
上文我的推测与实验在《Your Unix: The Ultimate Guide》这本2001年(甚至更早)出版的图书中同样得到了验证:
截图来自于谷歌图书
这更说明了这一习惯由来已久。
0x06
但由于网络安全的重视、动态网站的推广、建站系统的出现、PC的普及,当用户不再需要共享一台计算机,而这台计算机也无需24小时开机以服务随时访问的用户时,用户目录的特性被逐渐弃用,这一点也能在WebServer后起之秀Nginx中有所体现。Nginx完全不提供对用户目录的支持,相反建议用户自行实现该功能:
location ~ ^/~(.+?)(/.*)?$ {
alias /home/$1/public_html$2;
index index.html index.htm;
autoindex on;
}
0x07
关于~
符号的起源、历史、作用就谈到这里为止了。但眼尖的读者似乎发现了一个问题:为什么同样是特殊符号,~
符号不会被浏览器转义呢?
事实上,如果按照映射规则,~
符号本应该被URLENCODE为%7e
,即显示为例如https://example.com/%7euser/index.html
的样式,而按照RFC1738中的相关要求,我们也应该对其进行转义,才能应用在URL中。
而当我们将上文例子中两个URL的~
修改为%7e
之后,会发现浏览器的行为是自动恢复成~
符号,正常访问;而使用curl
也是可以正常访问的,这说明实际上WebServer和浏览器都同时兼容这两种方案,这也是一种兼容性考量。
0x08
但我们也必须承认,这种未经转义在URL中传递特殊字符的方法是错误的。
首先,这种方法将Unix的习惯带入了Web,但当时第一批这样做的管理员们没意识到一个问题:Web会变得如此庞大。当不了解UNIX的用户输入这样『奇怪』的URL时,一定会感到困扰,更别提有很多的键盘在输入这一少见符号时的困难,尤其是在非英语国家,例如欧洲:
这是一把芬兰语键盘,你可以一眼看出如何输入
~
符号吗?
其次,这种方法url与实际目录的映射也是非常规的。当我们看到~username/index.html
,而兴冲冲在UNIX Shell中键入cat ~username/index.html
时候,大多会遇到No such file or directory
错误,这是因为实际文件存放在~username/public_html/index.html
,这与常识背道而驰,也不便于自动化脚本的执行(要在最后一个fragment前的/
插入/public_html
字符,我想就算是精通awk
也要思考好一阵子才能想到如何实现)。
再者,在Linux尚还处于襁褓期、BSD只活在实验室与俱乐部里的上世纪90年代,使用~
作为家目录简写(甚至可以说存在家目录这一概念)的也只有UNIX,而至于DOS、Windows NT、OS/2、Macintosh OS(Old Mac)等操作系统,则完全不存在这一个概念,这一特性可能会让Unix下的WebServer部署较为简单,但却为Web的普及以及其部署造成了很大影响,反而弊大于利。
这就是URL中~
符号的故事,也是互联网早期各种有趣历史中的一小段,希望看到这里的读者能够领悟我的用意,能够和我一样,以后来者的眼光看待这段趣事,并能自然地会心一笑。