分块代理后面的 pkg 出现问题

分块代理后面的 pkg 出现问题

我在虚拟机中新安装了 FreeBSD 10.1。由于它位于公司代理后面,我必须设置HTTP_PROXY环境并且它开始运行良好。

但没有办法正常pkg工作。我从 ports 安装了它,仍然有同样的问题:

root@FriBi:~ # pkg update -f
Updating FreeBSD repository catalogue...
pkg: repository meta /var/db/pkg/FreeBSD.meta has wrong version or wrong format
Fetching meta.txz:   0%
pkg: No signature found
pkg: repository FreeBSD has no meta file, using default settings
Fetching packagesite.txz:   0%
pkg: No signature found
pkg: Unable to update repository FreeBSD
root@FriBi:~ #

我终于能够绕过代理...并且它立即运行良好...所以我尝试分析 HTTP 对话框。公司代理总是发送Transfer-Encoding: chunked我怀疑是原因的响应。我什至可以通过使用最小的 Python 代理来确认:

  • readall()通过缓冲整个文件从公司代理获取响应
  • 将其连同标头发送回ContentLength其客户端(此处pkg

然后它又起作用了(我可以做pkg install xorg......)

我的问题:

  • 真的对分块代理有pkg敌意还是可能是本地配置问题?
  • 如果是的话,是否应该在某处记录(找不到任何相关信息)
  • 有没有什么简单又好用的技巧(官方的proxy)将分块的 HTTP 响应转换为非分块的响应?

编辑

提议的补丁已集成在 1.5 版本中,该问题现已由该版本的 pkgng 解决。

答案1

此问题的最新进展:

  • 作为错误报告提交给 FreeBSD错误198772
  • 在邮件列表中提交freebsd 软件包并确认 pkg 1.4 无法处理分块响应
  • 建议补丁可以集成到即将发布的 1.5 pkg 版本中
  • (截至2015年4月25日)我可以确认该补丁已集成到1.5版本中,并且该版本当前在FreeBSD 10.1上使用:问题已解决。

这并不是一个真正的答案,但它可以帮助任何面临同样问题的人。以下是最小代理的 Python 代码,它整理以分块模式接收的整个文件,并使用 Content-Length 标头将其返回:

# -*- coding: latin1 -*-

import urllib.request
import http.server
import logging

class Handler(http.server.BaseHTTPRequestHandler):
    HEADERS = [ 'If-Modified-Since', 'Host', 'User-Agent', 'Accept',
                'Connection' ]
    def do_GET(self):
        logging.debug("Got a request %s", self.path)
        if self.server.debug >= 3:
            logging.debug("Original headers %s", self.headers.as_string())
        req = urllib.request.Request(self.path)
        for (key, value) in self.headers.items():
            if key in __class__.HEADERS:
                req.add_header(key, value)
        if self.server.debug >= 4:
            logging.debug("Send headers %s", str(req.headers))                
        r = self.server.opener.open(req)
        code = r.getcode()
        logging.debug('Code %d', code)
        if self.server.debug >= 3:
            logging.debug("Received headers %s", str(r.headers))
        if code == 200 and self.server.chunk:
            self.send_response(code)
            self.send_header('Transfer-Encoding', 'chunked')
            self.end_headers()
            while True:
                t = r.read(4095)
                logging.debug('Chunk : %d', len(t))
                self.wfile.write(("%03x\r\n" % (len(t),)).encode())
                if len(t) == 0:
                    self.wfile.write(b"\r\n")
                    break
                else:
                    self.wfile.write(t)
                    self.wfile.write(b"\r\n")
        else:
            t = r.readall()
            #print(t)
            self.send_response(code)
            logging.debug('Content-Length %d', len(t))
            self.send_header('Content-Length', len(t))
            self.end_headers()
            self.wfile.write(t)

class MiniProxy(http.server.HTTPServer):
    def __init__(self, port=8080, relay=None, chunk=False, debug=0):
        http.server.HTTPServer.__init__(self, ('', port), Handler)
        self.port = port
        self.relay = relay
        self.chunk = chunk
        self.debug= debug
        if relay is not None:
            logging.info("relay set to", relay)
            self.proxyHandler = urllib.request.ProxyHandler(
                {'http': relay})
            self.opener = urllib.request.build_opener(self.proxyHandler)
        else:
            self.opener = urllib.request.build_opener()

if __name__ == '__main__':
    import sys
    import argparse
    parser = argparse.ArgumentParser(description =
                      "Simple HTTP proxy to chunk or unchunk responses")
    parser.add_argument('-c', '--chunk', dest = 'chunk', action='store_true')
    parser.add_argument('-C', '--no-chunk', dest = 'chunk', action='store_false')
    parser.add_argument('-r', '--relay')
    parser.add_argument('-p', '--port', type=int,  default = 8080)
    parser.add_argument('-d', '--debug', type=int, default = 0)
    params = parser.parse_args()
    proxy = MiniProxy(port = params.port, relay = params.relay,
                      chunk = params.chunk, debug = params.debug)

    logging_format = '%(levelname)s:%(message)s'
    if params.debug == 1:
        logging.basicConfig(format=logging_format, level=logging.INFO)
    elif params.debug >= 2:
        logging.basicConfig(format=logging_format, level=logging.DEBUG)
    else:
        logging.basicConfig(format=logging_format)        
    try:
        print (sys.argv[0], "listen on", proxy.port)
        proxy.serve_forever()
    except KeyboardInterrupt:
        print('Stop')
        #proxy.shutdown()

相关内容