idna.py (6254B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\encodings\idna.py 2 import stringprep, re, codecs 3 from unicodedata import ucd_3_2_0 as unicodedata 4 dots = re.compile(u'[.\u3002\uff0e\uff61]') 5 ace_prefix = 'xn--' 6 uace_prefix = unicode(ace_prefix, 'ascii') 7 8 def nameprep(label): 9 newlabel = [] 10 for c in label: 11 if stringprep.in_table_b1(c): 12 continue 13 newlabel.append(stringprep.map_table_b2(c)) 14 15 label = u''.join(newlabel) 16 label = unicodedata.normalize('NFKC', label) 17 for c in label: 18 if stringprep.in_table_c12(c) or stringprep.in_table_c22(c) or stringprep.in_table_c3(c) or stringprep.in_table_c4(c) or stringprep.in_table_c5(c) or stringprep.in_table_c6(c) or stringprep.in_table_c7(c) or stringprep.in_table_c8(c) or stringprep.in_table_c9(c): 19 raise UnicodeError('Invalid character %r' % c) 20 21 RandAL = map(stringprep.in_table_d1, label) 22 for c in RandAL: 23 if c: 24 if filter(stringprep.in_table_d2, label): 25 raise UnicodeError('Violation of BIDI requirement 2') 26 if not RandAL[0] or not RandAL[-1]: 27 raise UnicodeError('Violation of BIDI requirement 3') 28 29 return label 30 31 32 def ToASCII(label): 33 try: 34 label = label.encode('ascii') 35 except UnicodeError: 36 pass 37 else: 38 if 0 < len(label) < 64: 39 return label 40 raise UnicodeError('label empty or too long') 41 42 label = nameprep(label) 43 try: 44 label = label.encode('ascii') 45 except UnicodeError: 46 pass 47 else: 48 if 0 < len(label) < 64: 49 return label 50 raise UnicodeError('label empty or too long') 51 52 if label.startswith(uace_prefix): 53 raise UnicodeError('Label starts with ACE prefix') 54 label = label.encode('punycode') 55 label = ace_prefix + label 56 if 0 < len(label) < 64: 57 return label 58 raise UnicodeError('label empty or too long') 59 60 61 def ToUnicode(label): 62 if isinstance(label, str): 63 pure_ascii = True 64 else: 65 try: 66 label = label.encode('ascii') 67 pure_ascii = True 68 except UnicodeError: 69 pure_ascii = False 70 71 if not pure_ascii: 72 label = nameprep(label) 73 try: 74 label = label.encode('ascii') 75 except UnicodeError: 76 raise UnicodeError('Invalid character in IDN label') 77 78 if not label.startswith(ace_prefix): 79 return unicode(label, 'ascii') 80 label1 = label[len(ace_prefix):] 81 result = label1.decode('punycode') 82 label2 = ToASCII(result) 83 if label.lower() != label2: 84 raise UnicodeError('IDNA does not round-trip', label, label2) 85 return result 86 87 88 class Codec(codecs.Codec): 89 90 def encode(self, input, errors = 'strict'): 91 if errors != 'strict': 92 raise UnicodeError('unsupported error handling ' + errors) 93 if not input: 94 return ('', 0) 95 result = [] 96 labels = dots.split(input) 97 if labels and len(labels[-1]) == 0: 98 trailing_dot = '.' 99 del labels[-1] 100 else: 101 trailing_dot = '' 102 for label in labels: 103 result.append(ToASCII(label)) 104 105 return ('.'.join(result) + trailing_dot, len(input)) 106 107 def decode(self, input, errors = 'strict'): 108 if errors != 'strict': 109 raise UnicodeError('Unsupported error handling ' + errors) 110 if not input: 111 return (u'', 0) 112 if isinstance(input, unicode): 113 labels = dots.split(input) 114 else: 115 input = str(input) 116 unicode(input, 'ascii') 117 labels = input.split('.') 118 if labels and len(labels[-1]) == 0: 119 trailing_dot = u'.' 120 del labels[-1] 121 else: 122 trailing_dot = u'' 123 result = [] 124 for label in labels: 125 result.append(ToUnicode(label)) 126 127 return (u'.'.join(result) + trailing_dot, len(input)) 128 129 130 class IncrementalEncoder(codecs.BufferedIncrementalEncoder): 131 132 def _buffer_encode(self, input, errors, final): 133 if errors != 'strict': 134 raise UnicodeError('unsupported error handling ' + errors) 135 if not input: 136 return ('', 0) 137 labels = dots.split(input) 138 trailing_dot = u'' 139 if labels: 140 if not labels[-1]: 141 trailing_dot = '.' 142 del labels[-1] 143 elif not final: 144 del labels[-1] 145 if labels: 146 trailing_dot = '.' 147 result = [] 148 size = 0 149 for label in labels: 150 result.append(ToASCII(label)) 151 if size: 152 size += 1 153 size += len(label) 154 155 result = '.'.join(result) + trailing_dot 156 size += len(trailing_dot) 157 return (result, size) 158 159 160 class IncrementalDecoder(codecs.BufferedIncrementalDecoder): 161 162 def _buffer_decode(self, input, errors, final): 163 if errors != 'strict': 164 raise UnicodeError('Unsupported error handling ' + errors) 165 if not input: 166 return (u'', 0) 167 if isinstance(input, unicode): 168 labels = dots.split(input) 169 else: 170 input = str(input) 171 unicode(input, 'ascii') 172 labels = input.split('.') 173 trailing_dot = u'' 174 if labels: 175 if not labels[-1]: 176 trailing_dot = u'.' 177 del labels[-1] 178 elif not final: 179 del labels[-1] 180 if labels: 181 trailing_dot = u'.' 182 result = [] 183 size = 0 184 for label in labels: 185 result.append(ToUnicode(label)) 186 if size: 187 size += 1 188 size += len(label) 189 190 result = u'.'.join(result) + trailing_dot 191 size += len(trailing_dot) 192 return (result, size) 193 194 195 class StreamWriter(Codec, codecs.StreamWriter): 196 pass 197 198 199 class StreamReader(Codec, codecs.StreamReader): 200 pass 201 202 203 def getregentry(): 204 return codecs.CodecInfo(name='idna', encode=Codec().encode, decode=Codec().decode, incrementalencoder=IncrementalEncoder, incrementaldecoder=IncrementalDecoder, streamwriter=StreamWriter, streamreader=StreamReader)