Golang source code COOKIE bug tracking

Cause

After the recent project was upgraded from golang0.9 to golang1.13, a very special phenomenon appeared in the project. In the APP, the user accesses the page normally after logging in, but the user does not log in and an error is reported.

Process

  1. Charles captured the packet and found that the service returned protobuf data when logged in, and json structure when not logged in. The service returns the corresponding data type based on the data passed in the cookie. It is preliminarily determined that cookies cannot be obtained without logging in

  2. Check the difference between cookies when logged in and not logged in.

    • Login: serviceToken=abc ;type=protobuf;session=123
    • Not logged in: ;type=protobuf;session=123

    The serviceToken is the authentication information after login. If the user is not logged in, the data does not exist, but the semicolon does exist. Initially suspected to be caused by the golang version

  3. Under the condition of the same code, use different golang versions to generate services and use scripts for testing

    <?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) ;
    

    Make sure it is a golang version problem

  4. View the source code, in net/http/cookie.go, you can see

    • golang1.12 split the cookie directly into strings.Split(strings.TrimSpace(line), ";"), so no matter where the semicolon is located, it can be parsed
    • In golang1.13, if splitIndex := strings.Index(line, “;”); splitIndex> 0, using this cutting method, if the quote is in the first one, the entire acquisition process is over, and the correct cookie value cannot be obtained.

    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
    }
    

to sum up

  1. Bold but cautious
    • This kind of upgrade is sometimes inevitable. The new version will have more new features and bring better performance. If the situation is right, you need to do it boldly.
    • Be sure to let the test students go through each terminal, various states, and various processes
    • After going online, you need to continue to observe
  2. When you encounter problems, you need to keep track of them. This is a process of self-growth and improvement
  3. Small aspects also need to be perfect, otherwise it will lead to a great price. Although the client-side method of writing cookies is correct, it is not very standard, and I didn't care when I wrote it. At present, the old version cannot be repaired. If you want to upgrade to 1.13, you must either fix the problem in golang or add the cookie processing logic to the project. It is a bit troublesome to deal with

At last

If you like my article, you can follow my public account (Programmer Mala Tang)

Review of previous articles:

  1. Redis implements distributed locks
  2. Golang source code bug tracking
  3. The realization principle of transaction atomicity, consistency and durability
  4. How to exercise your memory
  5. Detailed explanation of CDN request process
  6. Thoughts on the career development of programmers
  7. The history of blog service being crushed
  8. Common caching techniques
  9. How to efficiently connect with third-party payment
  10. Gin framework concise version
  11. Thinking about code review
  12. A brief analysis of InnoDB locks and transactions
  13. Markdown editor recommendation-typora

Guess you like

Origin blog.csdn.net/shida219/article/details/107137975