【问题标题】:sending http requests with specific/non-existent http version protocol in Python在 Python 中使用特定/不存在的 http 版本协议发送 http 请求
【发布时间】:2014-11-11 21:10:07
【问题描述】:

有一些方法可以在 python 中使用特定的 http 版本协议发送 http 请求。我认为,使用 httplib 或 urllib,这是不可能的。

例如:GET / HTTP/6.9

提前致谢。

【问题讨论】:

  • 为什么要这样做?您希望通过发送非法版本号来达到什么目的?
  • HTTP指纹识别,获取什么版本和型号的web服务器正在运行一个toe。
  • 是否有理由必须“使用 httplib 或 urllib”? (特别是因为后者已被弃用?)
  • 不,我曾想过用套接字来做这件事,但有人说我“不要重新发明轮子”

标签: python urllib httplib


【解决方案1】:

您的问题的简单答案是:您是对的,httpliburllib 都没有公开的内置功能来执行此操作。 (另外,你真的不应该在大多数事情上使用urllib——尤其是urlopen。)

当然,您始终可以依赖这些模块的实现细节,如Lukas Graf's answer

或者,您也可以分叉其中一个模块并对其进行修改,这样可以保证您的代码可以在其他 Python 2.x 实现上运行。*。请注意,httplib 是在顶部有指向the source 的链接的模块之一,这意味着它意味着将服务器作为示例代码,而不仅仅是作为黑盒库。

或者您可以只重新实现需要挂钩但已公开记录的最低级别的函数。对于httplib,我相信是httplib.HTTPConnection.putrequest,有几百行。

或者你可以选择一个不同的库,其中有更多的钩子,这样你就可以减少钩子了。

但实际上,如果您尝试制作自定义请求来手动识别结果,那么您为什么要使用 HTTP 库呢?为什么不这样做呢?

msg = 'GET / HTTP/6.9\r\n\r\n'
s = socket.create_connection((host, 80))
with closing(s):
    s.send(msg)
    buf = ''.join(iter(partial(s.recv, 4096), ''))

* 这没什么好处,因为永远不会有 2.8,所有现有的主要 2.7 实现都共享此模块的相同源,并且不太可能有任何新的 2.x 实现任何不同。如果你转到 3.x,httplib 已被重新组织和重命名,而 urllib 已被完全删除,所以你已经有更大的变化需要担心。

【讨论】:

    【解决方案2】:

    您可以通过继承httplib.HTTPConnection 并重新定义类属性_http_vsn_str 来轻松做到这一点:

    from httplib import HTTPConnection
    
    
    class MyHTTPConnection(HTTPConnection):
    
        _http_vsn_str = '6.9'
    
    
    conn = MyHTTPConnection("www.stackoverflow.com")
    conn.request("GET", "/")
    response = conn.getresponse()
    
    print "Status: {} {}".format(response.status, response.reason)
    print "Headers: {}".format(response.getheaders())
    print "Body: {}".format(response.read())
    

    当然,对于大多数服务器,这将导致400 Bad Request

    Status: 400 Bad Request
    Headers: [('date', 'Tue, 11 Nov 2014 21:21:12 GMT'), ('connection', 'close'), ('content-type', 'text/html; charset=us-ascii'), ('content-length', '311')]
    Body: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
    <HTML><HEAD><TITLE>Bad Request</TITLE>
    <META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
    <BODY><h2>Bad Request</h2>
    <hr><p>HTTP Error 400. The request is badly formed.</p>
    </BODY></HTML>
    

    【讨论】:

    • 我不喜欢这个。该属性的存在和目的不受合同保证。这可能会在 Python 的未来版本中中断。
    • @Kevin 很好 - 您正在将 HTTP 版本标识符更改为 6.9,同时仍在使用 HTTP 1.1。没有任何公共 API 会支持这个。
    • True...我想我真的很担心 OP 可能不应该首先尝试这样做。也许他们应该使用完全不同的技术。
    • @Kevin:那么答案是,“不,你不能用 Python 2.7 中的 httplib 来做到这一点”。但是您可以创建自己的 httplib 副本并对其进行修改或子类化,在这种情况下它保证
    • 是的,如果 HTTP 指纹识别是目的,这可能应该只在 TCP 套接字级别上完成。
    【解决方案3】:

    这可以通过使用此选项来使用 pycurl

    c.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_1_0)
    
    

    但是你需要使用 linux 或 mac,因为 pycurl 在 windows 上不受官方支持

    【讨论】:

      猜你喜欢
      • 2015-10-22
      • 2016-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-07
      • 1970-01-01
      相关资源
      最近更新 更多