135 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			135 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package url | ||
|  | 
 | ||
|  | import "strings" | ||
|  | 
 | ||
|  | var tblEscapeURLQuery = [128]byte{ | ||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
|  | 	0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, | ||
|  | } | ||
|  | 
 | ||
|  | var tblEscapeURLQueryParam = [128]byte{ | ||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, | ||
|  | 	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, | ||
|  | 	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, | ||
|  | } | ||
|  | 
 | ||
|  | // The code below is mostly borrowed from the standard Go url package | ||
|  | 
 | ||
|  | const upperhex = "0123456789ABCDEF" | ||
|  | 
 | ||
|  | func ishex(c byte) bool { | ||
|  | 	switch { | ||
|  | 	case '0' <= c && c <= '9': | ||
|  | 		return true | ||
|  | 	case 'a' <= c && c <= 'f': | ||
|  | 		return true | ||
|  | 	case 'A' <= c && c <= 'F': | ||
|  | 		return true | ||
|  | 	} | ||
|  | 	return false | ||
|  | } | ||
|  | 
 | ||
|  | func unhex(c byte) byte { | ||
|  | 	switch { | ||
|  | 	case '0' <= c && c <= '9': | ||
|  | 		return c - '0' | ||
|  | 	case 'a' <= c && c <= 'f': | ||
|  | 		return c - 'a' + 10 | ||
|  | 	case 'A' <= c && c <= 'F': | ||
|  | 		return c - 'A' + 10 | ||
|  | 	} | ||
|  | 	return 0 | ||
|  | } | ||
|  | 
 | ||
|  | func escape(s string, table *[128]byte, spaceToPlus bool) string { | ||
|  | 	spaceCount, hexCount := 0, 0 | ||
|  | 	for i := 0; i < len(s); i++ { | ||
|  | 		c := s[i] | ||
|  | 		if c > 127 || table[c] == 0 { | ||
|  | 			if c == ' ' && spaceToPlus { | ||
|  | 				spaceCount++ | ||
|  | 			} else { | ||
|  | 				hexCount++ | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if spaceCount == 0 && hexCount == 0 { | ||
|  | 		return s | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var sb strings.Builder | ||
|  | 	hexBuf := [3]byte{'%', 0, 0} | ||
|  | 
 | ||
|  | 	sb.Grow(len(s) + 2*hexCount) | ||
|  | 
 | ||
|  | 	for i := 0; i < len(s); i++ { | ||
|  | 		switch c := s[i]; { | ||
|  | 		case c == ' ' && spaceToPlus: | ||
|  | 			sb.WriteByte('+') | ||
|  | 		case c > 127 || table[c] == 0: | ||
|  | 			hexBuf[1] = upperhex[c>>4] | ||
|  | 			hexBuf[2] = upperhex[c&15] | ||
|  | 			sb.Write(hexBuf[:]) | ||
|  | 		default: | ||
|  | 			sb.WriteByte(c) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return sb.String() | ||
|  | } | ||
|  | 
 | ||
|  | func unescapeSearchParam(s string) string { | ||
|  | 	n := 0 | ||
|  | 	hasPlus := false | ||
|  | 	for i := 0; i < len(s); { | ||
|  | 		switch s[i] { | ||
|  | 		case '%': | ||
|  | 			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { | ||
|  | 				i++ | ||
|  | 				continue | ||
|  | 			} | ||
|  | 			n++ | ||
|  | 			i += 3 | ||
|  | 		case '+': | ||
|  | 			hasPlus = true | ||
|  | 			i++ | ||
|  | 		default: | ||
|  | 			i++ | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if n == 0 && !hasPlus { | ||
|  | 		return s | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var t strings.Builder | ||
|  | 	t.Grow(len(s) - 2*n) | ||
|  | 	for i := 0; i < len(s); i++ { | ||
|  | 		switch s[i] { | ||
|  | 		case '%': | ||
|  | 			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { | ||
|  | 				t.WriteByte('%') | ||
|  | 			} else { | ||
|  | 				t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2])) | ||
|  | 				i += 2 | ||
|  | 			} | ||
|  | 		case '+': | ||
|  | 			t.WriteByte(' ') | ||
|  | 		default: | ||
|  | 			t.WriteByte(s[i]) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return t.String() | ||
|  | } |