在 py2 下找到了
self.path
self.client_address
self.command
self.requestline
self.request_version
历史原因暂时只能用 py2
1
vast0906 OP 目前在群里根据大佬提示通过查找 headers 找到的一种解法,还有其他的办法吗?
|
2
lcdtyph 2019-09-03 22:48:06 +08:00
@vast0906
只有 http 的话没有了,就算是查找 header 也不是一定能拿到域名的,因为 http 协议没有规定必须专递那几个 header,也没有要求传输域名。 但是如果有 tls 的话可以在 tls 这一层拿到访问的域名,因为 client hello 的 sni 部分携带了请求的域名。 |
3
ochatokori 2019-09-03 23:23:38 +08:00 via Android
http 头里面的 host 就是啊
|
4
also24 2019-09-03 23:41:28 +08:00
@lcdtyph #2
HTTP 1.1 的标准里,header 里的 host 字段是必须的 参见 RFC: https://tools.ietf.org/html/rfc2616#page-129 A client MUST include a Host header field in all HTTP/1.1 request messages . |
5
lcdtyph 2019-09-03 23:46:41 +08:00
|
6
binux 2019-09-04 00:03:40 +08:00 via Android
@lcdtyph #5 即使 SimpleHTTPServer 只实现了 1.0 这和发送方有什么关系呢?发送的时候他又不知道对方是 1.0 的。
|
7
also24 2019-09-04 00:07:33 +08:00
@lcdtyph #5
根据我从下面的代码看到的情况,是可以支持 1.1 的(确切来说,是支持 1.1 的 keepalive 特性), 不过需要手动设置一下 protocol_version ( # Set this to HTTP/1.1 to enable automatic keepalive ) https://github.com/python/cpython/blob/2.7/Lib/BaseHTTPServer.py#L270 https://github.com/python/cpython/blob/2.7/Lib/BaseHTTPServer.py#L513 另外,host 字段是否存在,其实主要取决于你发起请求的客户端使用的版本啊,你 1.1 的请求已经自带 host header 了。 当然,假如你一定要考虑 1.0 的请求,其实也有一定可能能从 URI 里读取到的: https://tools.ietf.org/html/rfc1945#page-24 翻到这里发现一件事,那就是 1.0 时,如果这样读不到,其它的 Web Server 也读不到,不用纠结。 |
8
lcdtyph 2019-09-04 00:14:47 +08:00
|
9
binux 2019-09-04 00:22:10 +08:00
@lcdtyph 你考虑非正常请求干嘛?读不到 host 就返回 400 就好了呗。
如果我在前面放个 cdn,你不发送 host,难不成还要靠猜吗? |
10
also24 2019-09-04 00:25:47 +08:00
@lcdtyph #8
一个 “恶意” 的客户端,如何做到: 让 Web Server 拿到正确的域名(从而正常分发 vhost ) 却又 不让 Web Application 拿到正确的域名(从而无法取出 host 字段) 请注意: 只传递正确的 SNI,但传递错误的 host 字段,不但会欺骗 Web Application, 事实上在 Web Server 也会被欺骗,此时就已经跑到错误的 vhost 去了。 另外如果采取 SNI 的方式,你的 SSL 负载要靠 Web Server 来卸载 还是靠 SimpleHTTPServer 来卸载呢? 靠 Web Server 来卸载的话,哪儿来的 SNI 信息呢?靠 SimpleHTTPServer 卸载的话,好像不支持吧? 以及,我甚至不需要考虑恶意的客户端,对于 IE6 IE7 这种不支持 SNI 的浏览器,是不是又变成了拿不到了呢? 其实并不是:SimpleHTTPServer 没有“一定”能拿到域名的方法。 而应当是:任何的 Web Server 都没有 没有“一定”能拿到域名的方法。 在当前的环境下,我认为 HTTP 1.1 可以当做事实上的最优选择。 |
11
lcdtyph 2019-09-04 00:46:22 +08:00
@also24
只支持 http1.1 的 server 的确是可以的。我本来的想法是,本应在下层就可以 abort 掉的错误就不要扔给上层处理,比如这种场景下只使用 SimpleHTTPServer 是做不到这点的,是我莫名预设了条件,my bad。 --- 只传递正确的 SNI,但是不传递 host 字段,这种错误在 web server 反代时直接就返回 400 了,不需要 http 的上层来处理这种问题;另外 ssl 卸载靠 web server,反代的时候直接把 sni 信息塞进一个 header 转发给 simplehttpserver 就行了,因为 webserver 是可信的。我以为 lz 就是不想在 web app 里 handle 这种事情才来问的,所以以为需求是如果进入了 web app 就一定要能拿到域名。 |
12
also24 2019-09-04 01:11:19 +08:00 1
@lcdtyph #11
首先我觉得你预设了楼主认为 “一定拿到真实 host ” 的需求,我没有看到楼主要求这个。 楼主问这个的原因,我猜测是因为 BaseHTTPServer 没有 self.host,让楼主有些懵如何自己获取。 相对应的,例如 flask 有 flask.Request.host,django 有 django.http.HttpRequest.get_host,都可以直接取。 https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request.host https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.get_host 那么他们都是怎么取的呢?我比较懒,只翻了 flask,层层追溯可以找到这里: https://github.com/pallets/werkzeug/blob/master/src/werkzeug/wsgi.py#L145 而 django,其实上面贴的文档里已经讲了,相比直接去 host 字段,还考虑了反代的场景。 至于:ssl 卸载靠 web server,反代的时候直接把 sni 信息塞进一个 header 转发给 simplehttpserver 就行了。 不妨调研一下,想要实现这样的效果,应该怎样去具体实现,怕不是要写个 nginx 插件才行? 最后,关于 “ webserver 是可信的”,不妨看一下著名的 WebServer Nginx 是怎样处理请求的: http://nginx.org/en/docs/http/request_processing.html 我想,你应该能看到大量的 ' “ Host ” header field ' 这样的字眼,我就不多说了。 |
13
conn4575 2019-09-04 03:58:10 +08:00 via Android
根据 http 协议标准,这个只能从 header 里获取,虽然绝大部分情况都能拿的到,但是协议本身没有强制要求,例如如果用 curl 请求的话就没有
|
14
vast0906 OP |