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  	h := Header{
    49  		"a": nil,
    50  		"b": nil,
    51  		"c": nil,
    52  	}
    53  	sorter := new(sorter)
    54  
    55  	if allocs := testing.AllocsPerRun(5, func() {
    56  		if len(sorter.Keys(h)) != 3 {
    57  			t.Fatal("wrong result")
    58  		}
    59  	}); allocs > 0 {
    60  		t.Logf("Keys allocs = %v; want <1", allocs)
    61  	}
    62  }
    63  
    64  // waitCondition reports whether fn eventually returned true,
    65  // checking immediately and then every checkEvery amount,
    66  // until waitFor has elapsed, at which point it returns false.
    67  func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
    68  	deadline := time.Now().Add(waitFor)
    69  	for time.Now().Before(deadline) {
    70  		if fn() {
    71  			return true
    72  		}
    73  		time.Sleep(checkEvery)
    74  	}
    75  	return false
    76  }
    77  
    78  // waitErrCondition is like waitCondition but with errors instead of bools.
    79  func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
    80  	deadline := time.Now().Add(waitFor)
    81  	var err error
    82  	for time.Now().Before(deadline) {
    83  		if err = fn(); err == nil {
    84  			return nil
    85  		}
    86  		time.Sleep(checkEvery)
    87  	}
    88  	return err
    89  }
    90  
    91  func equalError(a, b error) bool {
    92  	if a == nil {
    93  		return b == nil
    94  	}
    95  	if b == nil {
    96  		return a == nil
    97  	}
    98  	return a.Error() == b.Error()
    99  }
   100  
   101  var forbiddenStringsFunctions = map[string]bool{
   102  	// Functions that use Unicode-aware case folding.
   103  	"EqualFold":      true,
   104  	"Title":          true,
   105  	"ToLower":        true,
   106  	"ToLowerSpecial": true,
   107  	"ToTitle":        true,
   108  	"ToTitleSpecial": true,
   109  	"ToUpper":        true,
   110  	"ToUpperSpecial": true,
   111  
   112  	// Functions that use Unicode-aware spaces.
   113  	"Fields":    true,
   114  	"TrimSpace": true,
   115  }
   116  
   117  // TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware
   118  // strings and bytes package functions. HTTP is mostly ASCII based, and doing
   119  // Unicode-aware case folding or space stripping can introduce vulnerabilities.
   120  func TestNoUnicodeStrings(t *testing.T) {
   121  	re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`)
   122  	if err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
   123  		if err != nil {
   124  			t.Fatal(err)
   125  		}
   126  
   127  		if path == "h2i" || path == "h2c" {
   128  			return filepath.SkipDir
   129  		}
   130  		if !strings.HasSuffix(path, ".go") ||
   131  			strings.HasSuffix(path, "_test.go") ||
   132  			path == "ascii.go" || info.IsDir() {
   133  			return nil
   134  		}
   135  
   136  		contents, err := os.ReadFile(path)
   137  		if err != nil {
   138  			t.Fatal(err)
   139  		}
   140  		for lineNum, line := range strings.Split(string(contents), "\n") {
   141  			for _, match := range re.FindAllStringSubmatch(line, -1) {
   142  				if !forbiddenStringsFunctions[match[2]] {
   143  					continue
   144  				}
   145  				t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1)
   146  			}
   147  		}
   148  
   149  		return nil
   150  	}); err != nil {
   151  		t.Fatal(err)
   152  	}
   153  }
   154  
   155  // SetForTest sets *p = v, and restores its original value in t.Cleanup.
   156  func SetForTest[T any](t testing.TB, p *T, v T) {
   157  	orig := *p
   158  	t.Cleanup(func() {
   159  		*p = orig
   160  	})
   161  	*p = v
   162  }
   163  
   164  // Must returns v if err is nil, or panics otherwise.
   165  func Must[T any](v T, err error) T {
   166  	if err != nil {
   167  		panic(err)
   168  	}
   169  	return v
   170  }
   171  

View as plain text