1  
     2  
     3  
     4  
     5  package httpguts
     6  
     7  import (
     8  	"net"
     9  	"strings"
    10  	"unicode/utf8"
    11  
    12  	"golang.org/x/net/idna"
    13  )
    14  
    15  var isTokenTable = [127]bool{
    16  	'!':  true,
    17  	'#':  true,
    18  	'$':  true,
    19  	'%':  true,
    20  	'&':  true,
    21  	'\'': true,
    22  	'*':  true,
    23  	'+':  true,
    24  	'-':  true,
    25  	'.':  true,
    26  	'0':  true,
    27  	'1':  true,
    28  	'2':  true,
    29  	'3':  true,
    30  	'4':  true,
    31  	'5':  true,
    32  	'6':  true,
    33  	'7':  true,
    34  	'8':  true,
    35  	'9':  true,
    36  	'A':  true,
    37  	'B':  true,
    38  	'C':  true,
    39  	'D':  true,
    40  	'E':  true,
    41  	'F':  true,
    42  	'G':  true,
    43  	'H':  true,
    44  	'I':  true,
    45  	'J':  true,
    46  	'K':  true,
    47  	'L':  true,
    48  	'M':  true,
    49  	'N':  true,
    50  	'O':  true,
    51  	'P':  true,
    52  	'Q':  true,
    53  	'R':  true,
    54  	'S':  true,
    55  	'T':  true,
    56  	'U':  true,
    57  	'W':  true,
    58  	'V':  true,
    59  	'X':  true,
    60  	'Y':  true,
    61  	'Z':  true,
    62  	'^':  true,
    63  	'_':  true,
    64  	'`':  true,
    65  	'a':  true,
    66  	'b':  true,
    67  	'c':  true,
    68  	'd':  true,
    69  	'e':  true,
    70  	'f':  true,
    71  	'g':  true,
    72  	'h':  true,
    73  	'i':  true,
    74  	'j':  true,
    75  	'k':  true,
    76  	'l':  true,
    77  	'm':  true,
    78  	'n':  true,
    79  	'o':  true,
    80  	'p':  true,
    81  	'q':  true,
    82  	'r':  true,
    83  	's':  true,
    84  	't':  true,
    85  	'u':  true,
    86  	'v':  true,
    87  	'w':  true,
    88  	'x':  true,
    89  	'y':  true,
    90  	'z':  true,
    91  	'|':  true,
    92  	'~':  true,
    93  }
    94  
    95  func IsTokenRune(r rune) bool {
    96  	i := int(r)
    97  	return i < len(isTokenTable) && isTokenTable[i]
    98  }
    99  
   100  func isNotToken(r rune) bool {
   101  	return !IsTokenRune(r)
   102  }
   103  
   104  
   105  
   106  func HeaderValuesContainsToken(values []string, token string) bool {
   107  	for _, v := range values {
   108  		if headerValueContainsToken(v, token) {
   109  			return true
   110  		}
   111  	}
   112  	return false
   113  }
   114  
   115  
   116  
   117  func isOWS(b byte) bool { return b == ' ' || b == '\t' }
   118  
   119  
   120  
   121  func trimOWS(x string) string {
   122  	
   123  	
   124  	
   125  	
   126  	for len(x) > 0 && isOWS(x[0]) {
   127  		x = x[1:]
   128  	}
   129  	for len(x) > 0 && isOWS(x[len(x)-1]) {
   130  		x = x[:len(x)-1]
   131  	}
   132  	return x
   133  }
   134  
   135  
   136  
   137  
   138  
   139  func headerValueContainsToken(v string, token string) bool {
   140  	for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') {
   141  		if tokenEqual(trimOWS(v[:comma]), token) {
   142  			return true
   143  		}
   144  		v = v[comma+1:]
   145  	}
   146  	return tokenEqual(trimOWS(v), token)
   147  }
   148  
   149  
   150  func lowerASCII(b byte) byte {
   151  	if 'A' <= b && b <= 'Z' {
   152  		return b + ('a' - 'A')
   153  	}
   154  	return b
   155  }
   156  
   157  
   158  func tokenEqual(t1, t2 string) bool {
   159  	if len(t1) != len(t2) {
   160  		return false
   161  	}
   162  	for i, b := range t1 {
   163  		if b >= utf8.RuneSelf {
   164  			
   165  			return false
   166  		}
   167  		if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
   168  			return false
   169  		}
   170  	}
   171  	return true
   172  }
   173  
   174  
   175  
   176  
   177  
   178  func isLWS(b byte) bool { return b == ' ' || b == '\t' }
   179  
   180  
   181  
   182  
   183  
   184  
   185  func isCTL(b byte) bool {
   186  	const del = 0x7f 
   187  	return b < ' ' || b == del
   188  }
   189  
   190  
   191  
   192  
   193  
   194  
   195  
   196  
   197  
   198  
   199  
   200  
   201  func ValidHeaderFieldName(v string) bool {
   202  	if len(v) == 0 {
   203  		return false
   204  	}
   205  	for _, r := range v {
   206  		if !IsTokenRune(r) {
   207  			return false
   208  		}
   209  	}
   210  	return true
   211  }
   212  
   213  
   214  func ValidHostHeader(h string) bool {
   215  	
   216  	
   217  	
   218  	
   219  	
   220  	
   221  	
   222  	
   223  	
   224  	
   225  	
   226  	for i := 0; i < len(h); i++ {
   227  		if !validHostByte[h[i]] {
   228  			return false
   229  		}
   230  	}
   231  	return true
   232  }
   233  
   234  
   235  var validHostByte = [256]bool{
   236  	'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
   237  	'8': true, '9': true,
   238  
   239  	'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
   240  	'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
   241  	'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
   242  	'y': true, 'z': true,
   243  
   244  	'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
   245  	'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
   246  	'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
   247  	'Y': true, 'Z': true,
   248  
   249  	'!':  true, 
   250  	'$':  true, 
   251  	'%':  true, 
   252  	'&':  true, 
   253  	'(':  true, 
   254  	')':  true, 
   255  	'*':  true, 
   256  	'+':  true, 
   257  	',':  true, 
   258  	'-':  true, 
   259  	'.':  true, 
   260  	':':  true, 
   261  	';':  true, 
   262  	'=':  true, 
   263  	'[':  true,
   264  	'\'': true, 
   265  	']':  true,
   266  	'_':  true, 
   267  	'~':  true, 
   268  }
   269  
   270  
   271  
   272  
   273  
   274  
   275  
   276  
   277  
   278  
   279  
   280  
   281  
   282  
   283  
   284  
   285  
   286  
   287  
   288  
   289  
   290  
   291  
   292  
   293  
   294  
   295  
   296  
   297  
   298  
   299  
   300  
   301  
   302  
   303  
   304  
   305  
   306  
   307  
   308  func ValidHeaderFieldValue(v string) bool {
   309  	for i := 0; i < len(v); i++ {
   310  		b := v[i]
   311  		if isCTL(b) && !isLWS(b) {
   312  			return false
   313  		}
   314  	}
   315  	return true
   316  }
   317  
   318  func isASCII(s string) bool {
   319  	for i := 0; i < len(s); i++ {
   320  		if s[i] >= utf8.RuneSelf {
   321  			return false
   322  		}
   323  	}
   324  	return true
   325  }
   326  
   327  
   328  
   329  func PunycodeHostPort(v string) (string, error) {
   330  	if isASCII(v) {
   331  		return v, nil
   332  	}
   333  
   334  	host, port, err := net.SplitHostPort(v)
   335  	if err != nil {
   336  		
   337  		
   338  		
   339  		host = v
   340  		port = ""
   341  	}
   342  	host, err = idna.ToASCII(host)
   343  	if err != nil {
   344  		
   345  		
   346  		return "", err
   347  	}
   348  	if port == "" {
   349  		return host, nil
   350  	}
   351  	return net.JoinHostPort(host, port), nil
   352  }
   353  
View as plain text