为了账号安全,请及时绑定邮箱和手机立即绑定

从.Net框架Bug的提交到修复代码成功合并到.NET CoreFX主线

标签:
Java

问题描述

我们用SmtpClientSendAsyncSendMailAsync异步方法发送邮件,并且要求使用DeliveryFormat = SmtpDeliveryFormat.SevenBit 格式来编码中文内容,本来预期是邮件内容中带中文的SubjectAttachments file name 都会进行Base64编码。

但实际结果是:如果邮件服务器支持SMTPUTF8扩展,那么异步发送SevenBit邮件并不会进行Base64编码,同步方法没有此问题。

问题根源

原因是在SmtpClient.SendMailCallback方法中,message.BeginSend allowUnicode参数直接使用的ServerSupportsEai,而不是统一的IsUnicodeSupported()

 private void SendMailCallback(IAsyncResult result)
 { 
    ......
     _message.BeginSend(_writer, DeliveryMethod != SmtpDeliveryMethod.Network, 
         ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState); 
    ......
 }

ServerSupportsEai改成IsUnicodeSupported()问题解决。就这20个字符的改动~

另外附对现有带Bug的.Net框架修复方法

比如使用的.NET Framework 4.7.2,纯天然原生自带此Bug,我们可以用我们的代码修复它。

最开始测试时以为此方法无效,没想到是Hook错了地方,换到最深层次调用地方,一抓一个准。

使用DotNetDetour库对.Net框架内方法进行Hook,找出SmtpClient.ServerSupportsEai最结果最终是从SmtpConnection.ServerSupportsEai得来的,也许是C#编译后把整个调用过程都优化掉了,变成了取值的地方直接调用的SmtpConnection中的方法,导致Hook前面的方法都是不会被执行,Hook SmtpConnection.ServerSupportsEai一抓一个准。

附上Hook代码:

public class Hook : IMethodMonitor {    public bool ServerSupportsEai {
        [Monitor("System.Net.Mail", "SmtpConnection")]
        get {
            Console.WriteLine("Hook");            return !true?org():false;//什么情况下要Hook? AsyncLocal和CallContext上下文为什么在这里传不进来?
        }
    }
    [Original]    public bool org() {        return false;
    }
}

另外引出了另外一个折磨人Bug,异步环境下,ServerSupportsEai的调用栈中上下文怎么会丢失?难道哪里使用了类似ThreadPool.UnsafeXXX这种效果?我们没法通过CallContext(AsyncLocal)给Hook代码传参数,只能写死,不管调用方要不要修改返回值,都只能得到修改后的结果,尴尬不尴尬。



作者:高坚果兄弟
链接:https://www.jianshu.com/p/b3dd5521f586


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消