最近碰到一个curl使用问题,现象是在终端里设置proxy环境变量然后curl没有生效,其他命令比如git clone、brew等等都是有效的,于是怀疑curl是不是有什么不为认知的特殊配置,想到这里就来了兴致,立马开始查起。最终发现是被自己遗忘的一个配置,属实大乌龙。

下面是终端执行过程中的输出,无论是否设置proxy curl都使用了另一个代理配置。

$ curl cip.cc
curl: (7) Failed to connect to 127.0.0.1 port 51837 after 8 ms: Connection refused
$ HTTP_PROXY=http://127.0.0.1:58591; export HTTPS_PROXY=http://127.0.0.1:58591; export ALL_PROXY=socks5://127.0.0.1:51838
$ curl cip.cc
curl: (7) Failed to connect to 127.0.0.1 port 51837 after 8 ms: Connection refused
$ unset HTTP_PROXY; unset HTTPS_PROXY; unset ALL_PROXY
$ curl cip.cc
curl: (7) Failed to connect to 127.0.0.1 port 51837 after 8 ms: Connection refused

一开始怀疑iterm2终端是不是有什么配置,于是换了Mac OS系统终端,发现还是一样的问题,排除终端问题。接着又怀疑是不是curl版本问题,使用brew安装了新版本的curl,问题依旧。再然后直接命令行里执行env命令,一股脑把全部环境变量都打了出来,并没有任何关于proxy的环境变量设置,有意思了,到底哪里出了问题呢?
作为一个程序员从源码里找答案是基本技能,于是从git clone了curl的源码,开始从代码里找curl设置proxy相关逻辑,终于发现curl除了会从环境变量里读proxy设置外还读了一个.curlrc的配置文件

/* return 0 on everything-is-fine, and non-zero otherwise */
int parseconfig(const char *filename, struct GlobalConfig *global)
{
  FILE *file = NULL;
  bool usedarg = FALSE;
  int rc = 0;
  struct OperationConfig *operation = global->last;
  char *pathalloc = NULL;

  if(!filename) {
    /* NULL means load .curlrc from homedir! */
    char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE);
    if(curlrc) {
      file = fopen(curlrc, FOPEN_READTEXT);
      if(!file) {
        free(curlrc);
        return 1;
      }
      filename = pathalloc = curlrc;
    }

虽然还没找到解析配置文件设置proxy相关的逻辑,但是可以先去home目录下看一下了,一看还真有个.curlrc的文件,5个月前创建的,打开一看只有一行配置socks5=127.0.0.1:51837。看到这里终于有了点印象,之前为了设置socks5 proxy就加了这么个配置,删掉重新执行curl终于正常了。