Source file src/net/http/internal/http2/http2_test.go

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http2
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"regexp"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
    19  
    20  func condSkipFailingTest(t *testing.T) {
    21  	if !*knownFailing {
    22  		t.Skip("Skipping known-failing test without --known_failing")
    23  	}
    24  }
    25  
    26  func init() {
    27  	DebugGoroutines = true
    28  	flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
    29  }
    30  
    31  func TestSettingString(t *testing.T) {
    32  	tests := []struct {
    33  		s    Setting
    34  		want string
    35  	}{
    36  		{Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
    37  		{Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
    38  	}
    39  	for i, tt := range tests {
    40  		got := fmt.Sprint(tt.s)
    41  		if got != tt.want {
    42  			t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
    43  		}
    44  	}
    45  }
    46  
    47  func TestSorterPoolAllocs(t *testing.T) {
    48  	ss := []string{"a", "b", "c"}
    49  	h := Header{
    50  		"a": nil,
    51  		"b": nil,
    52  		"c": nil,
    53  	}
    54  	sorter := new(sorter)
    55  
    56  	if allocs := testing.AllocsPerRun(100, func() {
    57  		sorter.SortStrings(ss)
    58  	}); allocs >= 1 {
    59  		t.Logf("SortStrings allocs = %v; want <1", allocs)
    60  	}
    61  
    62  	if allocs := testing.AllocsPerRun(5, func() {
    63  		if len(sorter.Keys(h)) != 3 {
    64  			t.Fatal("wrong result")
    65  		}
    66  	}); allocs > 0 {
    67  		t.Logf("Keys allocs = %v; want <1", allocs)
    68  	}
    69  }
    70  
    71  // waitCondition reports whether fn eventually returned true,
    72  // checking immediately and then every checkEvery amount,
    73  // until waitFor has elapsed, at which point it returns false.
    74  func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
    75  	deadline := time.Now().Add(waitFor)
    76  	for time.Now().Before(deadline) {
    77  		if fn() {
    78  			return true
    79  		}
    80  		time.Sleep(checkEvery)
    81  	}
    82  	return false
    83  }
    84  
    85  // waitErrCondition is like waitCondition but with errors instead of bools.
    86  func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
    87  	deadline := time.Now().Add(waitFor)
    88  	var err error
    89  	for time.Now().Before(deadline) {
    90  		if err = fn(); err == nil {
    91  			return nil
    92  		}
    93  		time.Sleep(checkEvery)
    94  	}
    95  	return err
    96  }
    97  
    98  func equalError(a, b error) bool {
    99  	if a == nil {
   100  		return b == nil
   101  	}
   102  	if b == nil {
   103  		return a == nil
   104  	}
   105  	return a.Error() == b.Error()
   106  }
   107  
   108  var forbiddenStringsFunctions = map[string]bool{
   109  	// Functions that use Unicode-aware case folding.
   110  	"EqualFold":      true,
   111  	"Title":          true,
   112  	"ToLower":        true,
   113  	"ToLowerSpecial": true,
   114  	"ToTitle":        true,
   115  	"ToTitleSpecial": true,
   116  	"ToUpper":        true,
   117  	"ToUpperSpecial": true,
   118  
   119  	// Functions that use Unicode-aware spaces.
   120  	"Fields":    true,
   121  	"TrimSpace": true,
   122  }
   123  
   124  // TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware
   125  // strings and bytes package functions. HTTP is mostly ASCII based, and doing
   126  // Unicode-aware case folding or space stripping can introduce vulnerabilities.
   127  func TestNoUnicodeStrings(t *testing.T) {
   128  	re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`)
   129  	if err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
   130  		if err != nil {
   131  			t.Fatal(err)
   132  		}
   133  
   134  		if path == "h2i" || path == "h2c" {
   135  			return filepath.SkipDir
   136  		}
   137  		if !strings.HasSuffix(path, ".go") ||
   138  			strings.HasSuffix(path, "_test.go") ||
   139  			path == "ascii.go" || info.IsDir() {
   140  			return nil
   141  		}
   142  
   143  		contents, err := os.ReadFile(path)
   144  		if err != nil {
   145  			t.Fatal(err)
   146  		}
   147  		for lineNum, line := range strings.Split(string(contents), "\n") {
   148  			for _, match := range re.FindAllStringSubmatch(line, -1) {
   149  				if !forbiddenStringsFunctions[match[2]] {
   150  					continue
   151  				}
   152  				t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1)
   153  			}
   154  		}
   155  
   156  		return nil
   157  	}); err != nil {
   158  		t.Fatal(err)
   159  	}
   160  }
   161  
   162  // SetForTest sets *p = v, and restores its original value in t.Cleanup.
   163  func SetForTest[T any](t testing.TB, p *T, v T) {
   164  	orig := *p
   165  	t.Cleanup(func() {
   166  		*p = orig
   167  	})
   168  	*p = v
   169  }
   170  
   171  // Must returns v if err is nil, or panics otherwise.
   172  func Must[T any](v T, err error) T {
   173  	if err != nil {
   174  		panic(err)
   175  	}
   176  	return v
   177  }
   178  

View as plain text