Source file src/net/http/range_test.go

     1  // Copyright 2011 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 http
     6  
     7  import (
     8  	"runtime/metrics"
     9  	"strings"
    10  	"testing"
    11  )
    12  
    13  var ParseRangeTests = []struct {
    14  	s      string
    15  	length int64
    16  	r      []httpRange
    17  }{
    18  	{"", 0, nil},
    19  	{"", 1000, nil},
    20  	{"foo", 0, nil},
    21  	{"bytes=", 0, nil},
    22  	{"bytes=7", 10, nil},
    23  	{"bytes= 7 ", 10, nil},
    24  	{"bytes=1-", 0, nil},
    25  	{"bytes=5-4", 10, nil},
    26  	{"bytes=0-2,5-4", 10, nil},
    27  	{"bytes=2-5,4-3", 10, nil},
    28  	{"bytes=--5,4--3", 10, nil},
    29  	{"bytes=A-", 10, nil},
    30  	{"bytes=A- ", 10, nil},
    31  	{"bytes=A-Z", 10, nil},
    32  	{"bytes= -Z", 10, nil},
    33  	{"bytes=5-Z", 10, nil},
    34  	{"bytes=Ran-dom, garbage", 10, nil},
    35  	{"bytes=0x01-0x02", 10, nil},
    36  	{"bytes=         ", 10, nil},
    37  	{"bytes= , , ,   ", 10, nil},
    38  
    39  	{"bytes=0-9", 10, []httpRange{{0, 10}}},
    40  	{"bytes=0-", 10, []httpRange{{0, 10}}},
    41  	{"bytes=5-", 10, []httpRange{{5, 5}}},
    42  	{"bytes=0-20", 10, []httpRange{{0, 10}}},
    43  	{"bytes=15-,0-5", 10, []httpRange{{0, 6}}},
    44  	{"bytes=1-2,5-", 10, []httpRange{{1, 2}, {5, 5}}},
    45  	{"bytes=-2 , 7-", 11, []httpRange{{9, 2}, {7, 4}}},
    46  	{"bytes=0-0 ,2-2, 7-", 11, []httpRange{{0, 1}, {2, 1}, {7, 4}}},
    47  	{"bytes=-5", 10, []httpRange{{5, 5}}},
    48  	{"bytes=-15", 10, []httpRange{{0, 10}}},
    49  	{"bytes=0-499", 10000, []httpRange{{0, 500}}},
    50  	{"bytes=500-999", 10000, []httpRange{{500, 500}}},
    51  	{"bytes=-500", 10000, []httpRange{{9500, 500}}},
    52  	{"bytes=9500-", 10000, []httpRange{{9500, 500}}},
    53  	{"bytes=0-0,-1", 10000, []httpRange{{0, 1}, {9999, 1}}},
    54  	{"bytes=500-600,601-999", 10000, []httpRange{{500, 101}, {601, 399}}},
    55  	{"bytes=500-700,601-999", 10000, []httpRange{{500, 201}, {601, 399}}},
    56  
    57  	// Match Apache laxity:
    58  	{"bytes=   1 -2   ,  4- 5, 7 - 8 , ,,", 11, []httpRange{{1, 2}, {4, 2}, {7, 2}}},
    59  }
    60  
    61  func TestParseRange(t *testing.T) {
    62  	for _, test := range ParseRangeTests {
    63  		r := test.r
    64  		ranges, err := parseRange(test.s, test.length)
    65  		if err != nil && r != nil {
    66  			t.Errorf("parseRange(%q) returned error %q", test.s, err)
    67  		}
    68  		if len(ranges) != len(r) {
    69  			t.Errorf("len(parseRange(%q)) = %d, want %d", test.s, len(ranges), len(r))
    70  			continue
    71  		}
    72  		for i := range r {
    73  			if ranges[i].start != r[i].start {
    74  				t.Errorf("parseRange(%q)[%d].start = %d, want %d", test.s, i, ranges[i].start, r[i].start)
    75  			}
    76  			if ranges[i].length != r[i].length {
    77  				t.Errorf("parseRange(%q)[%d].length = %d, want %d", test.s, i, ranges[i].length, r[i].length)
    78  			}
    79  		}
    80  	}
    81  }
    82  
    83  func TestParseRangeLimit(t *testing.T) {
    84  	for _, tc := range []struct {
    85  		name       string
    86  		godebug    string
    87  		numRanges  int
    88  		want       int
    89  		wantNonDef bool
    90  	}{
    91  		{
    92  			name:      "default limit not exceeded",
    93  			numRanges: defaultMaxContentRanges,
    94  			want:      defaultMaxContentRanges,
    95  		},
    96  		{
    97  			name:      "default limit exceeded",
    98  			numRanges: defaultMaxContentRanges + 1,
    99  			want:      0,
   100  		},
   101  		{
   102  			name:       "small limit exceeded",
   103  			godebug:    "httpservecontentmaxranges=10",
   104  			numRanges:  11,
   105  			want:       0,
   106  			wantNonDef: true,
   107  		},
   108  		{
   109  			name:      "small limit not exceeded",
   110  			godebug:   "httpservecontentmaxranges=10",
   111  			numRanges: 10,
   112  			want:      10,
   113  		},
   114  		{
   115  			name:       "disabled limit",
   116  			godebug:    "httpservecontentmaxranges=0",
   117  			numRanges:  2 * defaultMaxContentRanges,
   118  			want:       2 * defaultMaxContentRanges,
   119  			wantNonDef: true,
   120  		},
   121  		{
   122  			name:      "large limit exceeded",
   123  			godebug:   "httpservecontentmaxranges=300",
   124  			numRanges: 301,
   125  			want:      0,
   126  		},
   127  		{
   128  			name:       "large limit not exceeded",
   129  			godebug:    "httpservecontentmaxranges=300",
   130  			numRanges:  300,
   131  			want:       300,
   132  			wantNonDef: true,
   133  		},
   134  		{
   135  			name:      "large limit not exceeded by small input",
   136  			godebug:   "httpservecontentmaxranges=300",
   137  			numRanges: 10,
   138  			want:      10,
   139  		},
   140  		{
   141  			name:      "invalid limit negative",
   142  			godebug:   "httpservecontentmaxranges=-5",
   143  			numRanges: defaultMaxContentRanges + 1,
   144  			want:      0,
   145  		},
   146  		{
   147  			name:      "invalid limit non-numeric",
   148  			godebug:   "httpservecontentmaxranges=abc",
   149  			numRanges: defaultMaxContentRanges + 1,
   150  			want:      0,
   151  		},
   152  	} {
   153  		t.Run(tc.name, func(t *testing.T) {
   154  			t.Setenv("GODEBUG", tc.godebug)
   155  			var m [1]metrics.Sample
   156  			m[0].Name = "/godebug/non-default-behavior/httpservecontentmaxranges:events"
   157  			metrics.Read(m[:])
   158  			before := m[0].Value.Uint64()
   159  
   160  			rangeHeader := "bytes=" + strings.Repeat("0-0,", tc.numRanges-1) + "0-0"
   161  			ranges, err := parseRange(rangeHeader, 10_000_000)
   162  			if err != nil {
   163  				t.Fatalf("parseRange(%q): %v", rangeHeader, err)
   164  			}
   165  			if got := len(ranges); got != tc.want {
   166  				t.Errorf("len(ranges) = %v, want %v", got, tc.want)
   167  			}
   168  
   169  			metrics.Read(m[:])
   170  			after := m[0].Value.Uint64()
   171  			if tc.wantNonDef && after <= before {
   172  				t.Errorf("metric did not increment: before=%d, after=%d", before, after)
   173  			} else if !tc.wantNonDef && after != before {
   174  				t.Errorf("metric unexpectedly incremented: before=%d, after=%d", before, after)
   175  			}
   176  		})
   177  	}
   178  }
   179  

View as plain text