|  | // Copyright 2012 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package cookiejar | 
|  |  | 
|  | // This file implements the Punycode algorithm from RFC 3492. | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "strings" | 
|  | "unicode/utf8" | 
|  | ) | 
|  |  | 
|  | // These parameter values are specified in section 5. | 
|  | // | 
|  | // All computation is done with int32s, so that overflow behavior is identical | 
|  | // regardless of whether int is 32-bit or 64-bit. | 
|  | const ( | 
|  | base        int32 = 36 | 
|  | damp        int32 = 700 | 
|  | initialBias int32 = 72 | 
|  | initialN    int32 = 128 | 
|  | skew        int32 = 38 | 
|  | tmax        int32 = 26 | 
|  | tmin        int32 = 1 | 
|  | ) | 
|  |  | 
|  | // encode encodes a string as specified in section 6.3 and prepends prefix to | 
|  | // the result. | 
|  | // | 
|  | // The "while h < length(input)" line in the specification becomes "for | 
|  | // remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. | 
|  | func encode(prefix, s string) (string, error) { | 
|  | output := make([]byte, len(prefix), len(prefix)+1+2*len(s)) | 
|  | copy(output, prefix) | 
|  | delta, n, bias := int32(0), initialN, initialBias | 
|  | b, remaining := int32(0), int32(0) | 
|  | for _, r := range s { | 
|  | if r < utf8.RuneSelf { | 
|  | b++ | 
|  | output = append(output, byte(r)) | 
|  | } else { | 
|  | remaining++ | 
|  | } | 
|  | } | 
|  | h := b | 
|  | if b > 0 { | 
|  | output = append(output, '-') | 
|  | } | 
|  | for remaining != 0 { | 
|  | m := int32(0x7fffffff) | 
|  | for _, r := range s { | 
|  | if m > r && r >= n { | 
|  | m = r | 
|  | } | 
|  | } | 
|  | delta += (m - n) * (h + 1) | 
|  | if delta < 0 { | 
|  | return "", fmt.Errorf("cookiejar: invalid label %q", s) | 
|  | } | 
|  | n = m | 
|  | for _, r := range s { | 
|  | if r < n { | 
|  | delta++ | 
|  | if delta < 0 { | 
|  | return "", fmt.Errorf("cookiejar: invalid label %q", s) | 
|  | } | 
|  | continue | 
|  | } | 
|  | if r > n { | 
|  | continue | 
|  | } | 
|  | q := delta | 
|  | for k := base; ; k += base { | 
|  | t := k - bias | 
|  | if t < tmin { | 
|  | t = tmin | 
|  | } else if t > tmax { | 
|  | t = tmax | 
|  | } | 
|  | if q < t { | 
|  | break | 
|  | } | 
|  | output = append(output, encodeDigit(t+(q-t)%(base-t))) | 
|  | q = (q - t) / (base - t) | 
|  | } | 
|  | output = append(output, encodeDigit(q)) | 
|  | bias = adapt(delta, h+1, h == b) | 
|  | delta = 0 | 
|  | h++ | 
|  | remaining-- | 
|  | } | 
|  | delta++ | 
|  | n++ | 
|  | } | 
|  | return string(output), nil | 
|  | } | 
|  |  | 
|  | func encodeDigit(digit int32) byte { | 
|  | switch { | 
|  | case 0 <= digit && digit < 26: | 
|  | return byte(digit + 'a') | 
|  | case 26 <= digit && digit < 36: | 
|  | return byte(digit + ('0' - 26)) | 
|  | } | 
|  | panic("cookiejar: internal error in punycode encoding") | 
|  | } | 
|  |  | 
|  | // adapt is the bias adaptation function specified in section 6.1. | 
|  | func adapt(delta, numPoints int32, firstTime bool) int32 { | 
|  | if firstTime { | 
|  | delta /= damp | 
|  | } else { | 
|  | delta /= 2 | 
|  | } | 
|  | delta += delta / numPoints | 
|  | k := int32(0) | 
|  | for delta > ((base-tmin)*tmax)/2 { | 
|  | delta /= base - tmin | 
|  | k += base | 
|  | } | 
|  | return k + (base-tmin+1)*delta/(delta+skew) | 
|  | } | 
|  |  | 
|  | // Strictly speaking, the remaining code below deals with IDNA (RFC 5890 and | 
|  | // friends) and not Punycode (RFC 3492) per se. | 
|  |  | 
|  | // acePrefix is the ASCII Compatible Encoding prefix. | 
|  | const acePrefix = "xn--" | 
|  |  | 
|  | // toASCII converts a domain or domain label to its ASCII form. For example, | 
|  | // toASCII("bücher.example.com") is "xn--bcher-kva.example.com", and | 
|  | // toASCII("golang") is "golang". | 
|  | func toASCII(s string) (string, error) { | 
|  | if ascii(s) { | 
|  | return s, nil | 
|  | } | 
|  | labels := strings.Split(s, ".") | 
|  | for i, label := range labels { | 
|  | if !ascii(label) { | 
|  | a, err := encode(acePrefix, label) | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  | labels[i] = a | 
|  | } | 
|  | } | 
|  | return strings.Join(labels, "."), nil | 
|  | } | 
|  |  | 
|  | func ascii(s string) bool { | 
|  | for i := 0; i < len(s); i++ { | 
|  | if s[i] >= utf8.RuneSelf { | 
|  | return false | 
|  | } | 
|  | } | 
|  | return true | 
|  | } |