curl 中关于 CURLINFO_HEADER_SIZE 的 BUG 定位及修复
CentOS7 默认安装的 curl 版本太低了,需要升级为最新版。
1. 问题描述
对接了一个接口,用来下载 PDF 文件。使用 curl 下载后,文件老是报错无法打开。接口提供方直接返回的 PDF 二进制文件流,而没有放入某个字段中或经过 base64 编码。
负责下载的部分代码如下:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $this->get_service_url('General'));
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 总是会返回原生的(Raw)内容
    curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type:application/xml"));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $request_xml);
    $response = curl_exec($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); //头信息大小,curl 在这里有 BUG,需要升级到7.4 或 7.5
    $body = substr($response, $headerSize);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
...
}
接口返回报文:
HTTP/1.1 200 OK
Date: Mon, 14 May 2018 02:57:40 GMT
Server: Apache/2.4.33 (Win64) OpenSSL/1.1.0g
Content-Type: application/pdf
X-Powered-By: Servlet/2.5 JSP/2.1
Set-Cookie: JSESSIONID=HrNclQWb5KqehhTfsHl6tMAXRkdXHCuodVA3IWLnA8MbnYC2bQlJ!-2087621404; path=/; HttpOnly
Transfer-Encoding: chunked
通过 Fiddler 模拟请求的返回报文:
HTTP/1.1 200 OK
Date: Mon, 14 May 2018 01:31:12 GMT
Server: Apache/2.4.33 (Win64) OpenSSL/1.1.0g
Content-Type: application/pdf
X-Powered-By: Servlet/2.5 JSP/2.1
Set-Cookie: JSESSIONID=DGRcRdwrflVjDkUKAW-kCz6JnXKuVWFhEGXk9eNtDnfd-NNfH4jO!-2087621404; path=/; HttpOnly
Content-Length: 955521
%PDF-1.4
%
2 0 obj
<</Length 3857/Filter[/ASCII85Decode/FlateDecode]>>stream
Gb!Sn9<0VQ&`-m)s'aK0)=.6O&Eq/V+M3`I$XP-a8Vd]C-@\6[V(/J@1#mTh_)NG2FAGOZI4EcO
...
2. 查找问题根源
一番搜索后,发现了 PHP 中记录的 这个 BUG:如果使用了代理,此时 CURLINFO_HEADER_SIZE 字段会得到错误的头部长度。使用代理的情况下,返回的 HTTP Header 会多一行记录,导致头部长度计算错误:
HTTP/1.0 200 Connection established
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Thu, 03 Jan 2013 15:54:35 GMT
Server: Apache/2.2.22 (Amazon)
X-Powered-By: PHP/5.3.19
Content-Length: 15
Connection: Keep-alive
然后看一下下面的回复,是 curl 的问题。问题早就解决了,但是需要升级 curl 到 7.4 或更高版本。
我的报文没有使用代理啊。没多一行,但是还是先把 curl 升级了吧。查一下 CentOS7 使用的版本:
[root@VM_120_242_centos curl-7.59.0]# curl --version
curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.19.1 Basic ECC zlib/1.2.7 libidn/1.28 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz 
通过 CLI 调用 print_r 方法打印 curl 的版本,确认 PHP 使用的就是这个版本的 curl:了:
[root@VM_200_22_centos 1300_al]# php -r 'print_r( curl_version());'
Array
(
    [version_number] => 466176
    [age] => 3
    [features] => 34493
    [ssl_version_number] => 0
    [version] => 7.29.0
    [host] => x86_64-redhat-linux-gnu
    [ssl_version] => NSS/3.19.1 Basic ECC
    [libz_version] => 1.2.7
    [protocols] => Array
        (
            [0] => dict
            ...
        )
)
3. 升级 curl
升级 curl 到 7.4 或更高版本。在这里下载:curl 官方下载页面。
可以通过 yum 或源码安装,建议使用 yum,简单靠谱。
通过 yum 安装
1 添加 yum 仓库源
新建文件:
vim /etc/yum.repos.d/city-fan.repo
复制下面内容到这个文件中:
[CityFan]
name=City Fan Repo
baseurl=http://www.city-fan.org/ftp/contrib/yum-repo/rhel$releasever/$basearch/
enabled=1
gpgcheck=0
2 清除 yum 缓存
清除缓存目录下的软件包及旧的 headers:
yum clean all
3 安装
yum install curl 
4 确认
再次执行 curl --version 检查是否更新成功:
[root@VM_120_242_centos soft]# curl --version
curl 7.59.0 (x86_64-redhat-linux-gnu) libcurl/7.59.0 NSS/3.28.4 zlib/1.2.7 libpsl/0.7.0 (+libicu/50.1.2) libssh2/1.8.0 nghttp2/1.31.1
Release-Date: 2018-03-14
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz HTTP2 UnixSockets HTTPS-proxy PSL Metalink
5 重启所有依赖 curl 的软件
这里 PHP-FPM 需要重启:
systemctl restart php-fpm
通过源码安装(我是没成功)
1 下载
wget https://curl.haxx.se/download/curl-7.59.0.tar.gz
2 解压
tar -xzvf  curl-7.59.0.tar.gz
3 覆盖安装
cd curl-7.59.0
./configure
make
make install
4. 根本原因
PHP 中使用 curl 时,有这个一个选项:
curl_setopt($ch, CURLOPT_HEADER, 1); // 启用时会将头文件的信息作为数据流输出。
如果没有开启 CURLOPT_HEADER 这个选项,通过
$response = curl_exec($ch);
获取 curl 执行结果时,就是报文体了,不需要再分离 header 和 body,直接使用即可。所以代码修改如下:
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->get_service_url('General'));
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 总是会返回原生的(Raw)内容。
        curl_setopt($ch, CURLOPT_HEADER, 1); // 启用时会将头文件的信息作为数据流输出。
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type:application/xml"));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $request_xml);
        $response = curl_exec($ch);
        //分离 header 与 body
        $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); //头信息 size,curl 需要升级到7.4 或 7.5
        $header = substr($response, 0, $headerSize);
        $body = substr($response, $headerSize);
或
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->get_service_url('General'));
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 总是会返回原生的(Raw)内容。
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type:application/xml"));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $request_xml);
        $response = curl_exec($ch);
        //$response 就是报文体,不需要分离 header 与 body
        $body = $response;
总之,
- 如果不需要 header,则不需要开启 
CURLOPT_HEADER选项,直接读 curl 的响应信息即可。 - 如果需要 header,则开启 
CURLOPT_HEADER选项,此时需要分离 header 和 body。 
curl 中关于 CURLINFO_HEADER_SIZE 的 BUG 定位及修复的更多相关文章
- 一例 Go 编译器代码优化 bug 定位和修复解析
		
https://mp.weixin.qq.com/s/Tyl6dSb7mHBuqqN6WvEuaw
 - 【测试方法】Web测试中bug定位基本方法
		
知识总结:Web测试中bug定位基本方法 涉及知识点:测试方法 在web测试过程中,经常会遇到页面中内容或数据显示错误,甚至不显示,第一反应就是BUG,没错,确实是BUG.进一步了解这个BUG的问题出 ...
 - IOS9.0中hash值的bug与解决方案
		
事件起因 事情是这样的:产品上线发布,突然出现了问题.运营Gg过来反应,当场给露珠演示,运营同事的手机是iphone,bug确实是存在的.奇怪的是露珠用了其他iphone手机(借别人的,露珠的是吊死安 ...
 - (用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正
		
native支付模式一demo(用微信扫的静态链接二维码)BUG修复,一共4个BUG 1.native_call_qrcode.php这个文件中的代码无法生存native支付的短地址2.WxPayPu ...
 - 转载:BUG定位
		
1.web前端 Web前端就是通常说的网页.互联网公司的前端一般包含如下内容:JavaScript.ActionScript.CSS.HTML(..ML).Flash.交互式设计.视觉设计 web前端 ...
 - li在IE中底部空行的BUG
		
li在IE中底部空行的BUG 但是这次li在IE中底部出现的不是3像素而是一整条空白行,如图:HTML代码: <ul> <li><a href="#" ...
 - 【IE6的疯狂之九】li在IE中底部空行的BUG
		
曾经写过[IE6的疯狂之六]li在IE中底部3像素的BUG(增加浮动解决问题),原文地址:http://www.css88.com/archives/421: IE6 BUG大全: http://ww ...
 - curl中通过json格式吧post值返回到java中遇到中文乱码的问题
		
首先是: curl中模拟http请求: curl -l 127.0.0.1:8080/spacobj/core/do?acid=100 -H "token:101hh" -H &q ...
 - AngularJS进阶(十九)在AngularJS应用中集成百度地图实现定位功能
		
在AngularJS应用中集成百度地图实现定位功能 注:请点击此处进行充电! 前言 根据项目需求,需要实现手机定位功能,考虑到百度业务的强大能力,遂决定使用百度地图第三方服务. 添加第三方模块的步骤与 ...
 
随机推荐
- JAVA总结--jvm
			
VM,Virtual Machine 即虚拟机,指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算机系统. JVM,Java Virtual Machine 即Java虚拟机, ...
 - 初探LINUX之--基础知识篇
			
一 Linux哲学思想 1 一切都是一个文件(包含硬件) 2 小型,单一用途的程序 3 链接程序,共同完成复杂的任务 4 避免令人困惑的用户界面 5 配置数据存储在文本中 二 Linux重要概念 Sh ...
 - BZOJ 1100 &&luogu 3454(计算几何+KMP)
			
题面 给定一个多边形,求对称轴数量. 分析 初看这似乎是一道计算几何的题目,但是如果暴力枚举对称轴,再去判断对称轴两边的边和角是否相等,时间复杂度为\(O(n^2)\),显然会TLE 问题转换 顺时针 ...
 - 补码一位乘法(Booth算法,C语言实现)
			
补码一位乘法 首先了解下什么是补码? 补码概念的理解,需要先从“模”的概念开始. 我们可以把模理解为一个容器的容量.当超出这个 容量时,会自动溢出.如:我们最常见到的时钟,其容量 是 12,过了 12 ...
 - HDU-1269 迷宫城堡(连通分量)
			
迷宫城堡 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
 - Codeforces Round #503 (by SIS, Div. 2) C. Elections (暴力+贪心)
			
[题目描述] Elections are coming. You know the number of voters and the number of parties — n and m respe ...
 - 广告URL
			
讨厌的csdn 广告,百度搜索了一次,csdn cookie广告追了你好几年还有... 把下面的url 重定向127.0.0.1 ,只记录了百度广告,部分阿里的广告,其他还未记录 虽然也用Adblo ...
 - 微信公众号获取微信token
			
微信在公众号和小程序的开发都有开放文档一般看文档开发就行,很简单这里写一个小demo获取微信token,之后根据自己的业务获取信息处理即可 package com.demo.ccx; import o ...
 - Python之路-函数基础&局部变量与全局变量&匿名函数&递归函数&高阶函数
			
一.函数的定义与调用 函数:组织好的.可重复使用的.用户实现单一或者关联功能的代码段.函数能够提高应用的模块性和代码的重复利用率.Python提供了很多内置的函数,比如len等等,另外也可以根据自己的 ...
 - ABBYY FineReader 14.0.107.232 Enterprise 下载和安装使用
			
目录 1. 按 2. 软件功能 3. 软件特色 4. 安装说明 5. 激活说明 6. 下载地址 1. 按 ABBYY FineReader 是款功能强大的OCR文字识别软件:它支持者用户进行使用文档的 ...