ehForwarderBot / efb-wechat-slave

A channel for EH Forwarder Bot.
GNU Affero General Public License v3.0
458 stars 62 forks source link

无法发送文件 #49

Closed newdee closed 5 years ago

newdee commented 5 years ago

现在不止无法发送表情了,连文件都无法发送。

尝试发送word文档失败。

catbaron0 commented 5 years ago

目前已知的问题是,无法发送文件名为中文的文件。 可能有效 的解决方案在最后。

我大致追了一下,目测是 urllib3.fields 的历史遗留 bug 引起的。

当通过 urllib3 发送 post 请求的时候,如果 post 数据中 namefilename 字段内容是中文,则会导致发送失败。常见的解决方法是把这个字段留空。在 itchat.components.messages 中在处理 name 字段的时候用了留空处理,但是filename字段由于某种原因直接使用了文件名(猜测是 wx 服务器端要求使用这个字段),因此导致问题发生。稍微查了一下这个问题从 五年前 就在讨论了但是没有结果。(甚至连算不算 bug 都没有 定论 )

urllib3.fileds 的相关代码如下

def format_header_param(name, value):
    """
    Helper function to format and quote a single header parameter.

    Particularly useful for header parameters which might contain
    non-ASCII values, like file names. This follows RFC 2231, as
    suggested by RFC 2388 Section 4.4.

    :param name:
        The name of the parameter, a string expected to be ASCII only.
    :param value:
        The value of the parameter, provided as a unicode string.
    """
    if not any(ch in value for ch in '"\\\r\n'):
        result = '%s="%s"' % (name, value)
        try:
            result.encode('ascii')
        except (UnicodeEncodeError, UnicodeDecodeError):
            pass
        else:
            return result
    if not six.PY3 and isinstance(value, six.text_type):  # Python 2:
        value = value.encode('utf-8')
    value = email.utils.encode_rfc2231(value, 'utf-8') # <- bug 似乎是这里两行引起的
    value = '%s*=%s' % (name, value)
    return value

这里使用了 *= 是遵循 RFC 2231, chapter 4. 大致来说是表明 *=的内容包括了 language 和 character set 两个数据。这点在刚才给出的 issue 中也提到了。但这似乎会给中文字符带来问题。我自己的情况是,把 *= 替换为 = 之后中文文件就可用了。


以下是也许有效的解决方法

执行

cd $(pip3 show urllib3|grep Location|cut -d' ' -f2)'/urllib3/'
cp fields.py fields.py.bak
sed -i 's/\*=/=/' fields.py

之后重启 EFB

PS: urllib3 在今年3月更新了这段代码。我感觉问题应该还在,但是我没测试。有兴趣的话可以从 github 更新一下试试……

catbaron0 commented 5 years ago

最新的 urllib3 1.25.2 似乎已经修正了这个 bug。

通过更新 requestsurllib3 应该也可以解决。

你可以先用 pip 卸载当前的 urllib3requests然后重新安装。注意你可能需要多执行几次卸载来保证所有旧版本都被移除。

catbaron0 commented 5 years ago

更新了最新的 urllib3 之后,tg 无法从 wx 端接收中文文件名的文件。因为 ptb 11.0 使用了自己修改过的 urllib3,而这个 urllib3 中存在这个 bug。可以选择安装如下版本来解决。

efb-qq-slave (2.0.0a5)
efb-sticker2img-middleware (0.0.1)
efb-telegram-master (2.0.0b20)
efb-wechat-slave (2.0.0a18)
ehforwarderbot (2.0.0b15)
itchat (1.3.10)

如果希望使用 ptb 11,则可以之下以下命令来解决。

cd $(pip3 show python-telegram-bot|grep Location|cut -d' ' -f2)'/telegram/vendor/ptb_urllib3/urllib3/'
sudo cp fields.py fields.py.bak
sudo sed -i 's/\*=/=/' fields.py
blueset commented 5 years ago

相关 Issue: etm#54

kettly1260 commented 5 years ago

@catbaron0 用了这个方法之后接收到文件都会变成UTF8-xxxx这种乱码形式的名字的文件,请问这个有什么办法解决吗

catbaron0 commented 5 years ago

@catbaron0 用了这个方法之后接收到文件都会变成UTF8-xxxx这种乱码形式的名字的文件,请问这个有什么办法解决吗

迷。以前我记得没这个问题,不知道是什么地方更新了。而且最近我应该没空追这个问题……

kettly1260 commented 5 years ago

@catbaron0 用了这个方法之后接收到文件都会变成UTF8-xxxx这种乱码形式的名字的文件,请问这个有什么办法解决吗

迷。以前我记得没这个问题,不知道是什么地方更新了。而且最近我应该没空追这个问题……

不知道是不是这个原因引起的。之后的如果同时发送了多个文件,所有的文件都是同一个 @catbaron0 @blueset

blueset commented 5 years ago

之后的如果同时发送了多个文件,所有的文件都是同一个 @kettly1260

参见 #22。

blueset commented 5 years ago

目前在 ETM 方面通过 monkey-patching 实现了临时解决方案(workaround)。相关的中文讨论仍可在此讨论串继续。此问题的进一步更新仍会在 etm#54 进行发布。