折腾

everything about EP (Engineering Productivity)
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一个base64引发的血案

Posted on 2012-10-27 17:53  QualitySong  阅读(14670)  评论(0编辑  收藏  举报

一个同事,使用jira的REST api对jira进行修改,用python的httplib发请求,发现发出POST请求后,服务器总是返回json缺少close marker。

于是自己搞了个nginx,把post请求的内容打出来,发现后面的确少了2个字符,很奇怪,开始怀疑httplib对content-len的计算有问题,于是在httplib中加了一些print打印中间结果。把请求头和请求+body的字符串msg都打印出来

def _send_output(self, message_body=None):
        """Send the currently buffered request and clear the buffer.

        Appends an extra \\r\\n to the buffer.
        A message_body may be specified, to be appended to the request.
        """
        self._buffer.extend(("", ""))
        msg = "\r\n".join(self._buffer)
        print msg
        del self._buffer[:]
        # If msg and message_body are sent in a single send() call,
        # it will avoid performance problems caused by the interaction
        # between delayed ack and the Nagle algorithim.
        if isinstance(message_body, str):
            msg += message_body
            message_body = None
            print msg
        self.send(msg)
        if message_body is not None:
            #message_body was not a string (i.e. it is a file) and
            #we must run the risk of Nagle
            self.send(message_body)

结果发现header跟body之间多了一个换行符('\r\n'),http协议默认header和body之间有一个空行隔开,也就是一个只含有\r\n的行,但是多了一个\r\n,就会导致服务器取body的时候从这个多出来的\r\n开始取content-length个字符,这样body里最后的两个字符就被这个多出来的\r\n挤掉了

而通过观察,这个原因是由于header的最后一个字段Authorization: Basic eHh4eHh4eDp4eHh4eHh4后面多了一个"\n"导致,

这个字段的值是同事经过base64.encodestring("XXXXXX:XXXXXX")编码后得到的字符串,查看了一下python的lib doc,发现这个函数默认返回一个以"\n"结尾的字符串,这就这个问题的根本原因,replace掉其中的\n,一切就都OK了

base64.encodestring返回的字符串默认结尾带"\n",而且产生的base64编码字符串每76个字符就会用"\n"隔开,所以最安全的方法不是strip去掉结尾的\n,而是用replace去掉其中所有的\n。为啥base64.ecodestring每76字符就换行,这个是mime协议的规定,用于email发送,具体查看mime协议吧