Golang源码COOKIE BUG追查

栏目: IT技术 · 发布时间: 5年前

内容简介:最近的项目从golang0.9升级到golang1.13后,项目中出现了很特殊的现象,在APP里,用户登录后访问页面正常,用户不登录,报错。大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

起因

最近的项目从golang0.9升级到golang1.13后,项目中出现了很特殊的现象,在APP里,用户登录后访问页面正常,用户不登录,报错。

处理过程

  1. Charles抓包发现,登录的情况下,服务返回的是protobuf的数据,未登录情况下返回的是json结构。服务是根据cookie中传入的数据来返回对应的数据类型。初步断定未登录情况下无法获取到cookie

  2. 检查登录和未登录情况下cookie的区别。

    • 登录: serviceToken=abc ;type=protobuf;session=123
    • 未登录:;type=protobuf;session=123

    serviceToken是登录后的验证信息,用户如果未登录,数据不存在,但是分号却存在。初步怀疑是golang版本引起

  3. 在代码不变的情况下,使用不同golang版本生成服务,使用脚本进行测试

    <?php
    $url = "http://10.220.130.8:8081/in/app/sync";
    //$url = "http://in-go.buy.mi.com/in/app/sync";
    $cookie = "; xmuuid=XMGUEST-FCF117BF-4D1B-272F-829D-25E19826D4F8;type=protobuf";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_COOKIE, $cookie);
    $output = curl_exec($ch);
    curl_close($ch);
    var_dump($output,11) ;

    确定是golang版本问题

  4. 查看源码,在net/http/cookie.go中,可以看到

    • golang1.12将cookie直接做了分割strings.Split(strings.TrimSpace(line), ";"),所以无论分号在什么位置都能解析出来
    • 在golang1.13中 if splitIndex := strings.Index(line, ";"); splitIndex > 0 ,使用这种切割方式,如果引号位于第一个,整个获取过程便结束了,无法获得正确的cookie值

    golang1.12

    // readCookies parses all "Cookie" values from the header h and
    // returns the successfully parsed Cookies.
    //
    // if filter isn't empty, only cookies of that name are returned
    func readCookies(h Header, filter string) []*Cookie {
       lines, ok := h["Cookie"]
       if !ok {
          return []*Cookie{}
       }
    
       cookies := []*Cookie{}
       for _, line := range lines {
          parts := strings.Split(strings.TrimSpace(line), ";")
          if len(parts) == 1 && parts[0] == "" {
             continue
          }
          // Per-line attributes
          for i := 0; i < len(parts); i++ {
             parts[i] = strings.TrimSpace(parts[i])
             if len(parts[i]) == 0 {
                continue
             }
             name, val := parts[i], ""
             if j := strings.Index(name, "="); j >= 0 {
                name, val = name[:j], name[j+1:]
             }
             if !isCookieNameValid(name) {
                continue
             }
             if filter != "" && filter != name {
                continue
             }
             val, ok := parseCookieValue(val, true)
             if !ok {
                continue
             }
             cookies = append(cookies, &Cookie{Name: name, Value: val})
          }
       }
       return cookies
    }

    golang1.13

    // readCookies parses all "Cookie" values from the header h and
    // returns the successfully parsed Cookies.
    //
    // if filter isn't empty, only cookies of that name are returned
    func readCookies(h Header, filter string) []*Cookie {
       lines := h["Cookie"]
       if len(lines) == 0 {
          return []*Cookie{}
       }
    
       cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";"))
       for _, line := range lines {
          line = strings.TrimSpace(line)
          var part string
          for len(line) > 0 { // continue since we have rest
             if splitIndex := strings.Index(line, ";"); splitIndex > 0 {
                part, line = line[:splitIndex], line[splitIndex+1:]
             } else {
                part, line = line, ""
             }
             part = strings.TrimSpace(part)
             if len(part) == 0 {
                continue
             }
             name, val := part, ""
             if j := strings.Index(part, "="); j >= 0 {
                name, val = name[:j], name[j+1:]
             }
             if !isCookieNameValid(name) {
                continue
             }
             if filter != "" && filter != name {
                continue
             }
             val, ok := parseCookieValue(val, true)
             if !ok {
                continue
             }
             cookies = append(cookies, &Cookie{Name: name, Value: val})
          }
       }
       return cookies
    }

总结

  1. 胆大心细
    • 升级这种操作有时候是必然要做的,新版会有更多的新特性,带来更好的性能,情况合适的话,需要大胆去做
    • 一定要让测试同学,将各个终端,各种状态,各种流程过一遍
    • 上线之后,需要继续观察
  2. 遇到问题,需要不断追查,这是一个自我成长和提升的过程
  3. 小的方面也需要完美,否则会导致很大的代价。客户端写cookie的方法虽然没错,但也不是很标准,当时写的时候也没在意。目前老的版本已经无法修复,如果想升级1.13,要么修复golang里的问题,要么在项目里添加处理cookie的逻辑,处理起来都有些麻烦

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

Golang源码COOKIE BUG追查


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Django 1.0 Template Development

Django 1.0 Template Development

Scott Newman / Packt / 2008 / 24.99

Django is a high-level Python web application framework designed to support the rapid development of dynamic websites, web applications, and web services. Getting the most out of its template system a......一起来看看 《Django 1.0 Template Development》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具