...

Source file src/go.opentelemetry.io/otel/semconv/internal/http_test.go

Documentation: go.opentelemetry.io/otel/semconv/internal

     1  // Copyright The OpenTelemetry Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package internal
    15  
    16  import (
    17  	"crypto/tls"
    18  	"net/http"
    19  	"net/url"
    20  	"strings"
    21  	"testing"
    22  
    23  	"go.opentelemetry.io/otel/trace"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	"go.opentelemetry.io/otel/attribute"
    29  	"go.opentelemetry.io/otel/codes"
    30  )
    31  
    32  type tlsOption int
    33  
    34  const (
    35  	noTLS tlsOption = iota
    36  	withTLS
    37  )
    38  
    39  var sc = &SemanticConventions{
    40  	EnduserIDKey:                attribute.Key("enduser.id"),
    41  	HTTPClientIPKey:             attribute.Key("http.client_ip"),
    42  	HTTPFlavorKey:               attribute.Key("http.flavor"),
    43  	HTTPHostKey:                 attribute.Key("http.host"),
    44  	HTTPMethodKey:               attribute.Key("http.method"),
    45  	HTTPRequestContentLengthKey: attribute.Key("http.request_content_length"),
    46  	HTTPRouteKey:                attribute.Key("http.route"),
    47  	HTTPSchemeHTTP:              attribute.String("http.scheme", "http"),
    48  	HTTPSchemeHTTPS:             attribute.String("http.scheme", "https"),
    49  	HTTPServerNameKey:           attribute.Key("http.server_name"),
    50  	HTTPStatusCodeKey:           attribute.Key("http.status_code"),
    51  	HTTPTargetKey:               attribute.Key("http.target"),
    52  	HTTPURLKey:                  attribute.Key("http.url"),
    53  	HTTPUserAgentKey:            attribute.Key("http.user_agent"),
    54  	NetHostIPKey:                attribute.Key("net.host.ip"),
    55  	NetHostNameKey:              attribute.Key("net.host.name"),
    56  	NetHostPortKey:              attribute.Key("net.host.port"),
    57  	NetPeerIPKey:                attribute.Key("net.peer.ip"),
    58  	NetPeerNameKey:              attribute.Key("net.peer.name"),
    59  	NetPeerPortKey:              attribute.Key("net.peer.port"),
    60  	NetTransportIP:              attribute.String("net.transport", "ip"),
    61  	NetTransportOther:           attribute.String("net.transport", "other"),
    62  	NetTransportTCP:             attribute.String("net.transport", "ip_tcp"),
    63  	NetTransportUDP:             attribute.String("net.transport", "ip_udp"),
    64  	NetTransportUnix:            attribute.String("net.transport", "unix"),
    65  }
    66  
    67  func TestNetAttributesFromHTTPRequest(t *testing.T) {
    68  	type testcase struct {
    69  		name string
    70  
    71  		network string
    72  
    73  		method     string
    74  		requestURI string
    75  		proto      string
    76  		remoteAddr string
    77  		host       string
    78  		url        *url.URL
    79  		header     http.Header
    80  
    81  		expected []attribute.KeyValue
    82  	}
    83  	testcases := []testcase{
    84  		{
    85  			name:       "stripped, tcp",
    86  			network:    "tcp",
    87  			method:     "GET",
    88  			requestURI: "/user/123",
    89  			proto:      "HTTP/1.0",
    90  			remoteAddr: "",
    91  			host:       "",
    92  			url: &url.URL{
    93  				Path: "/user/123",
    94  			},
    95  			header: nil,
    96  			expected: []attribute.KeyValue{
    97  				attribute.String("net.transport", "ip_tcp"),
    98  			},
    99  		},
   100  		{
   101  			name:       "stripped, udp",
   102  			network:    "udp",
   103  			method:     "GET",
   104  			requestURI: "/user/123",
   105  			proto:      "HTTP/1.0",
   106  			remoteAddr: "",
   107  			host:       "",
   108  			url: &url.URL{
   109  				Path: "/user/123",
   110  			},
   111  			header: nil,
   112  			expected: []attribute.KeyValue{
   113  				attribute.String("net.transport", "ip_udp"),
   114  			},
   115  		},
   116  		{
   117  			name:       "stripped, ip",
   118  			network:    "ip",
   119  			method:     "GET",
   120  			requestURI: "/user/123",
   121  			proto:      "HTTP/1.0",
   122  			remoteAddr: "",
   123  			host:       "",
   124  			url: &url.URL{
   125  				Path: "/user/123",
   126  			},
   127  			header: nil,
   128  			expected: []attribute.KeyValue{
   129  				attribute.String("net.transport", "ip"),
   130  			},
   131  		},
   132  		{
   133  			name:       "stripped, unix",
   134  			network:    "unix",
   135  			method:     "GET",
   136  			requestURI: "/user/123",
   137  			proto:      "HTTP/1.0",
   138  			remoteAddr: "",
   139  			host:       "",
   140  			url: &url.URL{
   141  				Path: "/user/123",
   142  			},
   143  			header: nil,
   144  			expected: []attribute.KeyValue{
   145  				attribute.String("net.transport", "unix"),
   146  			},
   147  		},
   148  		{
   149  			name:       "stripped, other",
   150  			network:    "nih",
   151  			method:     "GET",
   152  			requestURI: "/user/123",
   153  			proto:      "HTTP/1.0",
   154  			remoteAddr: "",
   155  			host:       "",
   156  			url: &url.URL{
   157  				Path: "/user/123",
   158  			},
   159  			header: nil,
   160  			expected: []attribute.KeyValue{
   161  				attribute.String("net.transport", "other"),
   162  			},
   163  		},
   164  		{
   165  			name:       "with remote ipv4 and port",
   166  			network:    "tcp",
   167  			method:     "GET",
   168  			requestURI: "/user/123",
   169  			proto:      "HTTP/1.0",
   170  			remoteAddr: "1.2.3.4:56",
   171  			host:       "",
   172  			url: &url.URL{
   173  				Path: "/user/123",
   174  			},
   175  			header: nil,
   176  			expected: []attribute.KeyValue{
   177  				attribute.String("net.transport", "ip_tcp"),
   178  				attribute.String("net.peer.ip", "1.2.3.4"),
   179  				attribute.Int("net.peer.port", 56),
   180  			},
   181  		},
   182  		{
   183  			name:       "with remote ipv6 and port",
   184  			network:    "tcp",
   185  			method:     "GET",
   186  			requestURI: "/user/123",
   187  			proto:      "HTTP/1.0",
   188  			remoteAddr: "[fe80::0202:b3ff:fe1e:8329]:56",
   189  			host:       "",
   190  			url: &url.URL{
   191  				Path: "/user/123",
   192  			},
   193  			header: nil,
   194  			expected: []attribute.KeyValue{
   195  				attribute.String("net.transport", "ip_tcp"),
   196  				attribute.String("net.peer.ip", "fe80::202:b3ff:fe1e:8329"),
   197  				attribute.Int("net.peer.port", 56),
   198  			},
   199  		},
   200  		{
   201  			name:       "with remote ipv4-in-v6 and port",
   202  			network:    "tcp",
   203  			method:     "GET",
   204  			requestURI: "/user/123",
   205  			proto:      "HTTP/1.0",
   206  			remoteAddr: "[::ffff:192.168.0.1]:56",
   207  			host:       "",
   208  			url: &url.URL{
   209  				Path: "/user/123",
   210  			},
   211  			header: nil,
   212  			expected: []attribute.KeyValue{
   213  				attribute.String("net.transport", "ip_tcp"),
   214  				attribute.String("net.peer.ip", "192.168.0.1"),
   215  				attribute.Int("net.peer.port", 56),
   216  			},
   217  		},
   218  		{
   219  			name:       "with remote name and port",
   220  			network:    "tcp",
   221  			method:     "GET",
   222  			requestURI: "/user/123",
   223  			proto:      "HTTP/1.0",
   224  			remoteAddr: "example.com:56",
   225  			host:       "",
   226  			url: &url.URL{
   227  				Path: "/user/123",
   228  			},
   229  			header: nil,
   230  			expected: []attribute.KeyValue{
   231  				attribute.String("net.transport", "ip_tcp"),
   232  				attribute.String("net.peer.name", "example.com"),
   233  				attribute.Int("net.peer.port", 56),
   234  			},
   235  		},
   236  		{
   237  			name:       "with remote ipv4 only",
   238  			network:    "tcp",
   239  			method:     "GET",
   240  			requestURI: "/user/123",
   241  			proto:      "HTTP/1.0",
   242  			remoteAddr: "1.2.3.4",
   243  			host:       "",
   244  			url: &url.URL{
   245  				Path: "/user/123",
   246  			},
   247  			header: nil,
   248  			expected: []attribute.KeyValue{
   249  				attribute.String("net.transport", "ip_tcp"),
   250  				attribute.String("net.peer.ip", "1.2.3.4"),
   251  			},
   252  		},
   253  		{
   254  			name:       "with remote ipv6 only",
   255  			network:    "tcp",
   256  			method:     "GET",
   257  			requestURI: "/user/123",
   258  			proto:      "HTTP/1.0",
   259  			remoteAddr: "fe80::0202:b3ff:fe1e:8329",
   260  			host:       "",
   261  			url: &url.URL{
   262  				Path: "/user/123",
   263  			},
   264  			header: nil,
   265  			expected: []attribute.KeyValue{
   266  				attribute.String("net.transport", "ip_tcp"),
   267  				attribute.String("net.peer.ip", "fe80::202:b3ff:fe1e:8329"),
   268  			},
   269  		},
   270  		{
   271  			name:       "with remote ipv4_in_v6 only",
   272  			network:    "tcp",
   273  			method:     "GET",
   274  			requestURI: "/user/123",
   275  			proto:      "HTTP/1.0",
   276  			remoteAddr: "::ffff:192.168.0.1", // section 2.5.5.2 of RFC4291
   277  			host:       "",
   278  			url: &url.URL{
   279  				Path: "/user/123",
   280  			},
   281  			header: nil,
   282  			expected: []attribute.KeyValue{
   283  				attribute.String("net.transport", "ip_tcp"),
   284  				attribute.String("net.peer.ip", "192.168.0.1"),
   285  			},
   286  		},
   287  		{
   288  			name:       "with remote name only",
   289  			network:    "tcp",
   290  			method:     "GET",
   291  			requestURI: "/user/123",
   292  			proto:      "HTTP/1.0",
   293  			remoteAddr: "example.com",
   294  			host:       "",
   295  			url: &url.URL{
   296  				Path: "/user/123",
   297  			},
   298  			header: nil,
   299  			expected: []attribute.KeyValue{
   300  				attribute.String("net.transport", "ip_tcp"),
   301  				attribute.String("net.peer.name", "example.com"),
   302  			},
   303  		},
   304  		{
   305  			name:       "with remote port only",
   306  			network:    "tcp",
   307  			method:     "GET",
   308  			requestURI: "/user/123",
   309  			proto:      "HTTP/1.0",
   310  			remoteAddr: ":56",
   311  			host:       "",
   312  			url: &url.URL{
   313  				Path: "/user/123",
   314  			},
   315  			header: nil,
   316  			expected: []attribute.KeyValue{
   317  				attribute.String("net.transport", "ip_tcp"),
   318  				attribute.Int("net.peer.port", 56),
   319  			},
   320  		},
   321  		{
   322  			name:       "with host name only",
   323  			network:    "tcp",
   324  			method:     "GET",
   325  			requestURI: "/user/123",
   326  			proto:      "HTTP/1.0",
   327  			remoteAddr: "1.2.3.4:56",
   328  			host:       "example.com",
   329  			url: &url.URL{
   330  				Path: "/user/123",
   331  			},
   332  			header: nil,
   333  			expected: []attribute.KeyValue{
   334  				attribute.String("net.transport", "ip_tcp"),
   335  				attribute.String("net.peer.ip", "1.2.3.4"),
   336  				attribute.Int("net.peer.port", 56),
   337  				attribute.String("net.host.name", "example.com"),
   338  			},
   339  		},
   340  		{
   341  			name:       "with host ipv4 only",
   342  			network:    "tcp",
   343  			method:     "GET",
   344  			requestURI: "/user/123",
   345  			proto:      "HTTP/1.0",
   346  			remoteAddr: "1.2.3.4:56",
   347  			host:       "4.3.2.1",
   348  			url: &url.URL{
   349  				Path: "/user/123",
   350  			},
   351  			header: nil,
   352  			expected: []attribute.KeyValue{
   353  				attribute.String("net.transport", "ip_tcp"),
   354  				attribute.String("net.peer.ip", "1.2.3.4"),
   355  				attribute.Int("net.peer.port", 56),
   356  				attribute.String("net.host.ip", "4.3.2.1"),
   357  			},
   358  		},
   359  		{
   360  			name:       "with host ipv6 only",
   361  			network:    "tcp",
   362  			method:     "GET",
   363  			requestURI: "/user/123",
   364  			proto:      "HTTP/1.0",
   365  			remoteAddr: "1.2.3.4:56",
   366  			host:       "fe80::0202:b3ff:fe1e:8329",
   367  			url: &url.URL{
   368  				Path: "/user/123",
   369  			},
   370  			header: nil,
   371  			expected: []attribute.KeyValue{
   372  				attribute.String("net.transport", "ip_tcp"),
   373  				attribute.String("net.peer.ip", "1.2.3.4"),
   374  				attribute.Int("net.peer.port", 56),
   375  				attribute.String("net.host.ip", "fe80::202:b3ff:fe1e:8329"),
   376  			},
   377  		},
   378  		{
   379  			name:       "with host name and port",
   380  			network:    "tcp",
   381  			method:     "GET",
   382  			requestURI: "/user/123",
   383  			proto:      "HTTP/1.0",
   384  			remoteAddr: "1.2.3.4:56",
   385  			host:       "example.com:78",
   386  			url: &url.URL{
   387  				Path: "/user/123",
   388  			},
   389  			header: nil,
   390  			expected: []attribute.KeyValue{
   391  				attribute.String("net.transport", "ip_tcp"),
   392  				attribute.String("net.peer.ip", "1.2.3.4"),
   393  				attribute.Int("net.peer.port", 56),
   394  				attribute.String("net.host.name", "example.com"),
   395  				attribute.Int("net.host.port", 78),
   396  			},
   397  		},
   398  		{
   399  			name:       "with host ipv4 and port",
   400  			network:    "tcp",
   401  			method:     "GET",
   402  			requestURI: "/user/123",
   403  			proto:      "HTTP/1.0",
   404  			remoteAddr: "1.2.3.4:56",
   405  			host:       "4.3.2.1:78",
   406  			url: &url.URL{
   407  				Path: "/user/123",
   408  			},
   409  			header: nil,
   410  			expected: []attribute.KeyValue{
   411  				attribute.String("net.transport", "ip_tcp"),
   412  				attribute.String("net.peer.ip", "1.2.3.4"),
   413  				attribute.Int("net.peer.port", 56),
   414  				attribute.String("net.host.ip", "4.3.2.1"),
   415  				attribute.Int("net.host.port", 78),
   416  			},
   417  		},
   418  		{
   419  			name:       "with host ipv6 and port",
   420  			network:    "tcp",
   421  			method:     "GET",
   422  			requestURI: "/user/123",
   423  			proto:      "HTTP/1.0",
   424  			remoteAddr: "1.2.3.4:56",
   425  			host:       "[fe80::202:b3ff:fe1e:8329]:78",
   426  			url: &url.URL{
   427  				Path: "/user/123",
   428  			},
   429  			header: nil,
   430  			expected: []attribute.KeyValue{
   431  				attribute.String("net.transport", "ip_tcp"),
   432  				attribute.String("net.peer.ip", "1.2.3.4"),
   433  				attribute.Int("net.peer.port", 56),
   434  				attribute.String("net.host.ip", "fe80::202:b3ff:fe1e:8329"),
   435  				attribute.Int("net.host.port", 78),
   436  			},
   437  		},
   438  		{
   439  			name:       "with host name and bogus port",
   440  			network:    "tcp",
   441  			method:     "GET",
   442  			requestURI: "/user/123",
   443  			proto:      "HTTP/1.0",
   444  			remoteAddr: "1.2.3.4:56",
   445  			host:       "example.com:qwerty",
   446  			url: &url.URL{
   447  				Path: "/user/123",
   448  			},
   449  			header: nil,
   450  			expected: []attribute.KeyValue{
   451  				attribute.String("net.transport", "ip_tcp"),
   452  				attribute.String("net.peer.ip", "1.2.3.4"),
   453  				attribute.Int("net.peer.port", 56),
   454  				attribute.String("net.host.name", "example.com"),
   455  			},
   456  		},
   457  		{
   458  			name:       "with host ipv4 and bogus port",
   459  			network:    "tcp",
   460  			method:     "GET",
   461  			requestURI: "/user/123",
   462  			proto:      "HTTP/1.0",
   463  			remoteAddr: "1.2.3.4:56",
   464  			host:       "4.3.2.1:qwerty",
   465  			url: &url.URL{
   466  				Path: "/user/123",
   467  			},
   468  			header: nil,
   469  			expected: []attribute.KeyValue{
   470  				attribute.String("net.transport", "ip_tcp"),
   471  				attribute.String("net.peer.ip", "1.2.3.4"),
   472  				attribute.Int("net.peer.port", 56),
   473  				attribute.String("net.host.ip", "4.3.2.1"),
   474  			},
   475  		},
   476  		{
   477  			name:       "with host ipv6 and bogus port",
   478  			network:    "tcp",
   479  			method:     "GET",
   480  			requestURI: "/user/123",
   481  			proto:      "HTTP/1.0",
   482  			remoteAddr: "1.2.3.4:56",
   483  			host:       "[fe80::202:b3ff:fe1e:8329]:qwerty",
   484  			url: &url.URL{
   485  				Path: "/user/123",
   486  			},
   487  			header: nil,
   488  			expected: []attribute.KeyValue{
   489  				attribute.String("net.transport", "ip_tcp"),
   490  				attribute.String("net.peer.ip", "1.2.3.4"),
   491  				attribute.Int("net.peer.port", 56),
   492  				attribute.String("net.host.ip", "fe80::202:b3ff:fe1e:8329"),
   493  			},
   494  		},
   495  		{
   496  			name:       "with empty host and port",
   497  			network:    "tcp",
   498  			method:     "GET",
   499  			requestURI: "/user/123",
   500  			proto:      "HTTP/1.0",
   501  			remoteAddr: "1.2.3.4:56",
   502  			host:       ":80",
   503  			url: &url.URL{
   504  				Path: "/user/123",
   505  			},
   506  			header: nil,
   507  			expected: []attribute.KeyValue{
   508  				attribute.String("net.transport", "ip_tcp"),
   509  				attribute.String("net.peer.ip", "1.2.3.4"),
   510  				attribute.Int("net.peer.port", 56),
   511  				attribute.Int("net.host.port", 80),
   512  			},
   513  		},
   514  		{
   515  			name:       "with host ip and port in headers",
   516  			network:    "tcp",
   517  			method:     "GET",
   518  			requestURI: "/user/123",
   519  			proto:      "HTTP/1.0",
   520  			remoteAddr: "1.2.3.4:56",
   521  			host:       "",
   522  			url: &url.URL{
   523  				Path: "/user/123",
   524  			},
   525  			header: http.Header{
   526  				"Host": []string{"4.3.2.1:78"},
   527  			},
   528  			expected: []attribute.KeyValue{
   529  				attribute.String("net.transport", "ip_tcp"),
   530  				attribute.String("net.peer.ip", "1.2.3.4"),
   531  				attribute.Int("net.peer.port", 56),
   532  				attribute.String("net.host.ip", "4.3.2.1"),
   533  				attribute.Int("net.host.port", 78),
   534  			},
   535  		},
   536  		{
   537  			name:       "with host ipv4 and port in url",
   538  			network:    "tcp",
   539  			method:     "GET",
   540  			requestURI: "http://4.3.2.1:78/user/123",
   541  			proto:      "HTTP/1.0",
   542  			remoteAddr: "1.2.3.4:56",
   543  			host:       "",
   544  			url: &url.URL{
   545  				Host: "4.3.2.1:78",
   546  				Path: "/user/123",
   547  			},
   548  			header: nil,
   549  			expected: []attribute.KeyValue{
   550  				attribute.String("net.transport", "ip_tcp"),
   551  				attribute.String("net.peer.ip", "1.2.3.4"),
   552  				attribute.Int("net.peer.port", 56),
   553  				attribute.String("net.host.ip", "4.3.2.1"),
   554  				attribute.Int("net.host.port", 78),
   555  			},
   556  		},
   557  		{
   558  			name:       "with host ipv6 and port in url",
   559  			network:    "tcp",
   560  			method:     "GET",
   561  			requestURI: "http://4.3.2.1:78/user/123",
   562  			proto:      "HTTP/1.0",
   563  			remoteAddr: "1.2.3.4:56",
   564  			host:       "",
   565  			url: &url.URL{
   566  				Host: "[fe80::202:b3ff:fe1e:8329]:78",
   567  				Path: "/user/123",
   568  			},
   569  			header: nil,
   570  			expected: []attribute.KeyValue{
   571  				attribute.String("net.transport", "ip_tcp"),
   572  				attribute.String("net.peer.ip", "1.2.3.4"),
   573  				attribute.Int("net.peer.port", 56),
   574  				attribute.String("net.host.ip", "fe80::202:b3ff:fe1e:8329"),
   575  				attribute.Int("net.host.port", 78),
   576  			},
   577  		},
   578  	}
   579  	for _, tc := range testcases {
   580  		t.Run(tc.name, func(t *testing.T) {
   581  			r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, noTLS)
   582  			got := sc.NetAttributesFromHTTPRequest(tc.network, r)
   583  			if diff := cmp.Diff(
   584  				tc.expected,
   585  				got,
   586  				cmp.AllowUnexported(attribute.Value{})); diff != "" {
   587  				t.Fatalf("attributes differ: diff %+v,", diff)
   588  			}
   589  		})
   590  	}
   591  }
   592  
   593  func TestEndUserAttributesFromHTTPRequest(t *testing.T) {
   594  	r := testRequest("GET", "/user/123", "HTTP/1.1", "", "", nil, http.Header{}, withTLS)
   595  	var expected []attribute.KeyValue
   596  	got := sc.EndUserAttributesFromHTTPRequest(r)
   597  	assert.ElementsMatch(t, expected, got)
   598  	r.SetBasicAuth("admin", "password")
   599  	expected = []attribute.KeyValue{attribute.String("enduser.id", "admin")}
   600  	got = sc.EndUserAttributesFromHTTPRequest(r)
   601  	assert.ElementsMatch(t, expected, got)
   602  }
   603  
   604  func TestHTTPServerAttributesFromHTTPRequest(t *testing.T) {
   605  	type testcase struct {
   606  		name string
   607  
   608  		serverName string
   609  		route      string
   610  
   611  		method        string
   612  		requestURI    string
   613  		proto         string
   614  		remoteAddr    string
   615  		host          string
   616  		url           *url.URL
   617  		header        http.Header
   618  		tls           tlsOption
   619  		contentLength int64
   620  
   621  		expected []attribute.KeyValue
   622  	}
   623  	testcases := []testcase{
   624  		{
   625  			name:       "stripped",
   626  			serverName: "",
   627  			route:      "",
   628  			method:     "GET",
   629  			requestURI: "/user/123",
   630  			proto:      "HTTP/1.0",
   631  			remoteAddr: "",
   632  			host:       "",
   633  			url: &url.URL{
   634  				Path: "/user/123",
   635  			},
   636  			header: nil,
   637  			tls:    noTLS,
   638  			expected: []attribute.KeyValue{
   639  				attribute.String("http.method", "GET"),
   640  				attribute.String("http.target", "/user/123"),
   641  				attribute.String("http.scheme", "http"),
   642  				attribute.String("http.flavor", "1.0"),
   643  			},
   644  		},
   645  		{
   646  			name:       "with server name",
   647  			serverName: "my-server-name",
   648  			route:      "",
   649  			method:     "GET",
   650  			requestURI: "/user/123",
   651  			proto:      "HTTP/1.0",
   652  			remoteAddr: "",
   653  			host:       "",
   654  			url: &url.URL{
   655  				Path: "/user/123",
   656  			},
   657  			header: nil,
   658  			tls:    noTLS,
   659  			expected: []attribute.KeyValue{
   660  				attribute.String("http.method", "GET"),
   661  				attribute.String("http.target", "/user/123"),
   662  				attribute.String("http.scheme", "http"),
   663  				attribute.String("http.flavor", "1.0"),
   664  				attribute.String("http.server_name", "my-server-name"),
   665  			},
   666  		},
   667  		{
   668  			name:       "with tls",
   669  			serverName: "my-server-name",
   670  			route:      "",
   671  			method:     "GET",
   672  			requestURI: "/user/123",
   673  			proto:      "HTTP/1.0",
   674  			remoteAddr: "",
   675  			host:       "",
   676  			url: &url.URL{
   677  				Path: "/user/123",
   678  			},
   679  			header: nil,
   680  			tls:    withTLS,
   681  			expected: []attribute.KeyValue{
   682  				attribute.String("http.method", "GET"),
   683  				attribute.String("http.target", "/user/123"),
   684  				attribute.String("http.scheme", "https"),
   685  				attribute.String("http.flavor", "1.0"),
   686  				attribute.String("http.server_name", "my-server-name"),
   687  			},
   688  		},
   689  		{
   690  			name:       "with route",
   691  			serverName: "my-server-name",
   692  			route:      "/user/:id",
   693  			method:     "GET",
   694  			requestURI: "/user/123",
   695  			proto:      "HTTP/1.0",
   696  			remoteAddr: "",
   697  			host:       "",
   698  			url: &url.URL{
   699  				Path: "/user/123",
   700  			},
   701  			header: nil,
   702  			tls:    withTLS,
   703  			expected: []attribute.KeyValue{
   704  				attribute.String("http.method", "GET"),
   705  				attribute.String("http.target", "/user/123"),
   706  				attribute.String("http.scheme", "https"),
   707  				attribute.String("http.flavor", "1.0"),
   708  				attribute.String("http.server_name", "my-server-name"),
   709  				attribute.String("http.route", "/user/:id"),
   710  			},
   711  		},
   712  		{
   713  			name:       "with host",
   714  			serverName: "my-server-name",
   715  			route:      "/user/:id",
   716  			method:     "GET",
   717  			requestURI: "/user/123",
   718  			proto:      "HTTP/1.0",
   719  			remoteAddr: "",
   720  			host:       "example.com",
   721  			url: &url.URL{
   722  				Path: "/user/123",
   723  			},
   724  			header: nil,
   725  			tls:    withTLS,
   726  			expected: []attribute.KeyValue{
   727  				attribute.String("http.method", "GET"),
   728  				attribute.String("http.target", "/user/123"),
   729  				attribute.String("http.scheme", "https"),
   730  				attribute.String("http.flavor", "1.0"),
   731  				attribute.String("http.server_name", "my-server-name"),
   732  				attribute.String("http.route", "/user/:id"),
   733  				attribute.String("http.host", "example.com"),
   734  			},
   735  		},
   736  		{
   737  			name:       "with host fallback",
   738  			serverName: "my-server-name",
   739  			route:      "/user/:id",
   740  			method:     "GET",
   741  			requestURI: "/user/123",
   742  			proto:      "HTTP/1.0",
   743  			remoteAddr: "",
   744  			host:       "",
   745  			url: &url.URL{
   746  				Host: "example.com",
   747  				Path: "/user/123",
   748  			},
   749  			header: nil,
   750  			tls:    withTLS,
   751  			expected: []attribute.KeyValue{
   752  				attribute.String("http.method", "GET"),
   753  				attribute.String("http.target", "/user/123"),
   754  				attribute.String("http.scheme", "https"),
   755  				attribute.String("http.flavor", "1.0"),
   756  				attribute.String("http.server_name", "my-server-name"),
   757  				attribute.String("http.route", "/user/:id"),
   758  				attribute.String("http.host", "example.com"),
   759  			},
   760  		},
   761  		{
   762  			name:       "with user agent",
   763  			serverName: "my-server-name",
   764  			route:      "/user/:id",
   765  			method:     "GET",
   766  			requestURI: "/user/123",
   767  			proto:      "HTTP/1.0",
   768  			remoteAddr: "",
   769  			host:       "example.com",
   770  			url: &url.URL{
   771  				Path: "/user/123",
   772  			},
   773  			header: http.Header{
   774  				"User-Agent": []string{"foodownloader"},
   775  			},
   776  			tls: withTLS,
   777  			expected: []attribute.KeyValue{
   778  				attribute.String("http.method", "GET"),
   779  				attribute.String("http.target", "/user/123"),
   780  				attribute.String("http.scheme", "https"),
   781  				attribute.String("http.flavor", "1.0"),
   782  				attribute.String("http.server_name", "my-server-name"),
   783  				attribute.String("http.route", "/user/:id"),
   784  				attribute.String("http.host", "example.com"),
   785  				attribute.String("http.user_agent", "foodownloader"),
   786  			},
   787  		},
   788  		{
   789  			name:       "with proxy info",
   790  			serverName: "my-server-name",
   791  			route:      "/user/:id",
   792  			method:     "GET",
   793  			requestURI: "/user/123",
   794  			proto:      "HTTP/1.0",
   795  			remoteAddr: "",
   796  			host:       "example.com",
   797  			url: &url.URL{
   798  				Path: "/user/123",
   799  			},
   800  			header: http.Header{
   801  				"User-Agent":      []string{"foodownloader"},
   802  				"X-Forwarded-For": []string{"203.0.113.195, 70.41.3.18, 150.172.238.178"},
   803  			},
   804  			tls: withTLS,
   805  			expected: []attribute.KeyValue{
   806  				attribute.String("http.method", "GET"),
   807  				attribute.String("http.target", "/user/123"),
   808  				attribute.String("http.scheme", "https"),
   809  				attribute.String("http.flavor", "1.0"),
   810  				attribute.String("http.server_name", "my-server-name"),
   811  				attribute.String("http.route", "/user/:id"),
   812  				attribute.String("http.host", "example.com"),
   813  				attribute.String("http.user_agent", "foodownloader"),
   814  				attribute.String("http.client_ip", "203.0.113.195"),
   815  			},
   816  		},
   817  		{
   818  			name:       "with http 1.1",
   819  			serverName: "my-server-name",
   820  			route:      "/user/:id",
   821  			method:     "GET",
   822  			requestURI: "/user/123",
   823  			proto:      "HTTP/1.1",
   824  			remoteAddr: "",
   825  			host:       "example.com",
   826  			url: &url.URL{
   827  				Path: "/user/123",
   828  			},
   829  			header: http.Header{
   830  				"User-Agent":      []string{"foodownloader"},
   831  				"X-Forwarded-For": []string{"1.2.3.4"},
   832  			},
   833  			tls: withTLS,
   834  			expected: []attribute.KeyValue{
   835  				attribute.String("http.method", "GET"),
   836  				attribute.String("http.target", "/user/123"),
   837  				attribute.String("http.scheme", "https"),
   838  				attribute.String("http.flavor", "1.1"),
   839  				attribute.String("http.server_name", "my-server-name"),
   840  				attribute.String("http.route", "/user/:id"),
   841  				attribute.String("http.host", "example.com"),
   842  				attribute.String("http.user_agent", "foodownloader"),
   843  				attribute.String("http.client_ip", "1.2.3.4"),
   844  			},
   845  		},
   846  		{
   847  			name:       "with http 2",
   848  			serverName: "my-server-name",
   849  			route:      "/user/:id",
   850  			method:     "GET",
   851  			requestURI: "/user/123",
   852  			proto:      "HTTP/2.0",
   853  			remoteAddr: "",
   854  			host:       "example.com",
   855  			url: &url.URL{
   856  				Path: "/user/123",
   857  			},
   858  			header: http.Header{
   859  				"User-Agent":      []string{"foodownloader"},
   860  				"X-Forwarded-For": []string{"1.2.3.4"},
   861  			},
   862  			tls: withTLS,
   863  			expected: []attribute.KeyValue{
   864  				attribute.String("http.method", "GET"),
   865  				attribute.String("http.target", "/user/123"),
   866  				attribute.String("http.scheme", "https"),
   867  				attribute.String("http.flavor", "2"),
   868  				attribute.String("http.server_name", "my-server-name"),
   869  				attribute.String("http.route", "/user/:id"),
   870  				attribute.String("http.host", "example.com"),
   871  				attribute.String("http.user_agent", "foodownloader"),
   872  				attribute.String("http.client_ip", "1.2.3.4"),
   873  			},
   874  		},
   875  		{
   876  			name:          "with content length",
   877  			method:        "GET",
   878  			requestURI:    "/user/123",
   879  			contentLength: 100,
   880  			expected: []attribute.KeyValue{
   881  				attribute.String("http.method", "GET"),
   882  				attribute.String("http.target", "/user/123"),
   883  				attribute.String("http.scheme", "http"),
   884  				attribute.Int64("http.request_content_length", 100),
   885  			},
   886  		},
   887  	}
   888  	for idx, tc := range testcases {
   889  		r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
   890  		r.ContentLength = tc.contentLength
   891  		got := sc.HTTPServerAttributesFromHTTPRequest(tc.serverName, tc.route, r)
   892  		assertElementsMatch(t, tc.expected, got, "testcase %d - %s", idx, tc.name)
   893  	}
   894  }
   895  
   896  func TestHTTPAttributesFromHTTPStatusCode(t *testing.T) {
   897  	expected := []attribute.KeyValue{
   898  		attribute.Int("http.status_code", 404),
   899  	}
   900  	got := sc.HTTPAttributesFromHTTPStatusCode(http.StatusNotFound)
   901  	assertElementsMatch(t, expected, got, "with valid HTTP status code")
   902  	assert.ElementsMatch(t, expected, got)
   903  	expected = []attribute.KeyValue{
   904  		attribute.Int("http.status_code", 499),
   905  	}
   906  	got = sc.HTTPAttributesFromHTTPStatusCode(499)
   907  	assertElementsMatch(t, expected, got, "with invalid HTTP status code")
   908  }
   909  
   910  func TestSpanStatusFromHTTPStatusCode(t *testing.T) {
   911  	for code := 0; code < 1000; code++ {
   912  		expected := getExpectedCodeForHTTPCode(code, trace.SpanKindClient)
   913  		got, msg := SpanStatusFromHTTPStatusCode(code)
   914  		assert.Equalf(t, expected, got, "%s vs %s", expected, got)
   915  
   916  		_, valid := validateHTTPStatusCode(code)
   917  		if !valid {
   918  			assert.NotEmpty(t, msg, "message should be set if error cannot be inferred from code")
   919  		} else {
   920  			assert.Empty(t, msg, "message should not be set if error can be inferred from code")
   921  		}
   922  	}
   923  }
   924  
   925  func TestSpanStatusFromHTTPStatusCodeAndSpanKind(t *testing.T) {
   926  	for code := 0; code < 1000; code++ {
   927  		expected := getExpectedCodeForHTTPCode(code, trace.SpanKindClient)
   928  		got, msg := SpanStatusFromHTTPStatusCodeAndSpanKind(code, trace.SpanKindClient)
   929  		assert.Equalf(t, expected, got, "%s vs %s", expected, got)
   930  
   931  		_, valid := validateHTTPStatusCode(code)
   932  		if !valid {
   933  			assert.NotEmpty(t, msg, "message should be set if error cannot be inferred from code")
   934  		} else {
   935  			assert.Empty(t, msg, "message should not be set if error can be inferred from code")
   936  		}
   937  	}
   938  	code, _ := SpanStatusFromHTTPStatusCodeAndSpanKind(400, trace.SpanKindServer)
   939  	assert.Equalf(t, codes.Unset, code, "message should be set if error cannot be inferred from code")
   940  }
   941  
   942  func getExpectedCodeForHTTPCode(code int, spanKind trace.SpanKind) codes.Code {
   943  	if http.StatusText(code) == "" {
   944  		return codes.Error
   945  	}
   946  	switch code {
   947  	case
   948  		http.StatusUnauthorized,
   949  		http.StatusForbidden,
   950  		http.StatusNotFound,
   951  		http.StatusTooManyRequests,
   952  		http.StatusNotImplemented,
   953  		http.StatusServiceUnavailable,
   954  		http.StatusGatewayTimeout:
   955  		return codes.Error
   956  	}
   957  	category := code / 100
   958  	if category > 0 && category < 4 {
   959  		return codes.Unset
   960  	}
   961  	if spanKind == trace.SpanKindServer && category == 4 {
   962  		return codes.Unset
   963  	}
   964  	return codes.Error
   965  }
   966  
   967  func assertElementsMatch(t *testing.T, expected, got []attribute.KeyValue, format string, args ...interface{}) {
   968  	if !assert.ElementsMatchf(t, expected, got, format, args...) {
   969  		t.Log("expected:", kvStr(expected))
   970  		t.Log("got:", kvStr(got))
   971  	}
   972  }
   973  
   974  func testRequest(method, requestURI, proto, remoteAddr, host string, u *url.URL, header http.Header, tlsopt tlsOption) *http.Request {
   975  	major, minor := protoToInts(proto)
   976  	var tlsConn *tls.ConnectionState
   977  	switch tlsopt {
   978  	case noTLS:
   979  	case withTLS:
   980  		tlsConn = &tls.ConnectionState{}
   981  	}
   982  	return &http.Request{
   983  		Method:     method,
   984  		URL:        u,
   985  		Proto:      proto,
   986  		ProtoMajor: major,
   987  		ProtoMinor: minor,
   988  		Header:     header,
   989  		Host:       host,
   990  		RemoteAddr: remoteAddr,
   991  		RequestURI: requestURI,
   992  		TLS:        tlsConn,
   993  	}
   994  }
   995  
   996  func protoToInts(proto string) (int, int) {
   997  	switch proto {
   998  	case "HTTP/1.0":
   999  		return 1, 0
  1000  	case "HTTP/1.1":
  1001  		return 1, 1
  1002  	case "HTTP/2.0":
  1003  		return 2, 0
  1004  	}
  1005  	// invalid proto
  1006  	return 13, 42
  1007  }
  1008  
  1009  func kvStr(kvs []attribute.KeyValue) string {
  1010  	sb := strings.Builder{}
  1011  	_, _ = sb.WriteRune('[')
  1012  	for idx, attr := range kvs {
  1013  		if idx > 0 {
  1014  			_, _ = sb.WriteString(", ")
  1015  		}
  1016  		_, _ = sb.WriteString((string)(attr.Key))
  1017  		_, _ = sb.WriteString(": ")
  1018  		_, _ = sb.WriteString(attr.Value.Emit())
  1019  	}
  1020  	_, _ = sb.WriteRune(']')
  1021  	return sb.String()
  1022  }
  1023  
  1024  func TestHTTPClientAttributesFromHTTPRequest(t *testing.T) {
  1025  	testCases := []struct {
  1026  		name string
  1027  
  1028  		method        string
  1029  		requestURI    string
  1030  		proto         string
  1031  		remoteAddr    string
  1032  		host          string
  1033  		url           *url.URL
  1034  		header        http.Header
  1035  		tls           tlsOption
  1036  		contentLength int64
  1037  
  1038  		expected []attribute.KeyValue
  1039  	}{
  1040  		{
  1041  			name:       "stripped",
  1042  			method:     "GET",
  1043  			requestURI: "/user/123",
  1044  			proto:      "HTTP/1.0",
  1045  			remoteAddr: "",
  1046  			host:       "",
  1047  			url: &url.URL{
  1048  				Path: "/user/123",
  1049  			},
  1050  			header: nil,
  1051  			tls:    noTLS,
  1052  			expected: []attribute.KeyValue{
  1053  				attribute.String("http.method", "GET"),
  1054  				attribute.String("http.url", "/user/123"),
  1055  				attribute.String("http.scheme", "http"),
  1056  				attribute.String("http.flavor", "1.0"),
  1057  			},
  1058  		},
  1059  		{
  1060  			name:       "with tls",
  1061  			method:     "GET",
  1062  			requestURI: "/user/123",
  1063  			proto:      "HTTP/1.0",
  1064  			remoteAddr: "",
  1065  			host:       "",
  1066  			url: &url.URL{
  1067  				Path: "/user/123",
  1068  			},
  1069  			header: nil,
  1070  			tls:    withTLS,
  1071  			expected: []attribute.KeyValue{
  1072  				attribute.String("http.method", "GET"),
  1073  				attribute.String("http.url", "/user/123"),
  1074  				attribute.String("http.scheme", "https"),
  1075  				attribute.String("http.flavor", "1.0"),
  1076  			},
  1077  		},
  1078  		{
  1079  			name:       "with host",
  1080  			method:     "GET",
  1081  			requestURI: "/user/123",
  1082  			proto:      "HTTP/1.0",
  1083  			remoteAddr: "",
  1084  			host:       "example.com",
  1085  			url: &url.URL{
  1086  				Path: "/user/123",
  1087  			},
  1088  			header: nil,
  1089  			tls:    withTLS,
  1090  			expected: []attribute.KeyValue{
  1091  				attribute.String("http.method", "GET"),
  1092  				attribute.String("http.url", "/user/123"),
  1093  				attribute.String("http.scheme", "https"),
  1094  				attribute.String("http.flavor", "1.0"),
  1095  				attribute.String("http.host", "example.com"),
  1096  			},
  1097  		},
  1098  		{
  1099  			name:       "with host fallback",
  1100  			method:     "GET",
  1101  			requestURI: "/user/123",
  1102  			proto:      "HTTP/1.0",
  1103  			remoteAddr: "",
  1104  			host:       "",
  1105  			url: &url.URL{
  1106  				Scheme: "https",
  1107  				Host:   "example.com",
  1108  				Path:   "/user/123",
  1109  			},
  1110  			header: nil,
  1111  			tls:    withTLS,
  1112  			expected: []attribute.KeyValue{
  1113  				attribute.String("http.method", "GET"),
  1114  				attribute.String("http.url", "https://example.com/user/123"),
  1115  				attribute.String("http.scheme", "https"),
  1116  				attribute.String("http.flavor", "1.0"),
  1117  				attribute.String("http.host", "example.com"),
  1118  			},
  1119  		},
  1120  		{
  1121  			name:       "with user agent",
  1122  			method:     "GET",
  1123  			requestURI: "/user/123",
  1124  			proto:      "HTTP/1.0",
  1125  			remoteAddr: "",
  1126  			host:       "example.com",
  1127  			url: &url.URL{
  1128  				Path: "/user/123",
  1129  			},
  1130  			header: http.Header{
  1131  				"User-Agent": []string{"foodownloader"},
  1132  			},
  1133  			tls: withTLS,
  1134  			expected: []attribute.KeyValue{
  1135  				attribute.String("http.method", "GET"),
  1136  				attribute.String("http.url", "/user/123"),
  1137  				attribute.String("http.scheme", "https"),
  1138  				attribute.String("http.flavor", "1.0"),
  1139  				attribute.String("http.host", "example.com"),
  1140  				attribute.String("http.user_agent", "foodownloader"),
  1141  			},
  1142  		},
  1143  		{
  1144  			name:       "with http 1.1",
  1145  			method:     "GET",
  1146  			requestURI: "/user/123",
  1147  			proto:      "HTTP/1.1",
  1148  			remoteAddr: "",
  1149  			host:       "example.com",
  1150  			url: &url.URL{
  1151  				Path: "/user/123",
  1152  			},
  1153  			header: http.Header{
  1154  				"User-Agent": []string{"foodownloader"},
  1155  			},
  1156  			tls: withTLS,
  1157  			expected: []attribute.KeyValue{
  1158  				attribute.String("http.method", "GET"),
  1159  				attribute.String("http.url", "/user/123"),
  1160  				attribute.String("http.scheme", "https"),
  1161  				attribute.String("http.flavor", "1.1"),
  1162  				attribute.String("http.host", "example.com"),
  1163  				attribute.String("http.user_agent", "foodownloader"),
  1164  			},
  1165  		},
  1166  		{
  1167  			name:       "with http 2",
  1168  			method:     "GET",
  1169  			requestURI: "/user/123",
  1170  			proto:      "HTTP/2.0",
  1171  			remoteAddr: "",
  1172  			host:       "example.com",
  1173  			url: &url.URL{
  1174  				Path: "/user/123",
  1175  			},
  1176  			header: http.Header{
  1177  				"User-Agent": []string{"foodownloader"},
  1178  			},
  1179  			tls: withTLS,
  1180  			expected: []attribute.KeyValue{
  1181  				attribute.String("http.method", "GET"),
  1182  				attribute.String("http.url", "/user/123"),
  1183  				attribute.String("http.scheme", "https"),
  1184  				attribute.String("http.flavor", "2"),
  1185  				attribute.String("http.host", "example.com"),
  1186  				attribute.String("http.user_agent", "foodownloader"),
  1187  			},
  1188  		},
  1189  		{
  1190  			name:   "with content length",
  1191  			method: "GET",
  1192  			url: &url.URL{
  1193  				Path: "/user/123",
  1194  			},
  1195  			contentLength: 100,
  1196  			expected: []attribute.KeyValue{
  1197  				attribute.String("http.method", "GET"),
  1198  				attribute.String("http.url", "/user/123"),
  1199  				attribute.String("http.scheme", "http"),
  1200  				attribute.Int64("http.request_content_length", 100),
  1201  			},
  1202  		},
  1203  		{
  1204  			name:   "with empty method (fallback to GET)",
  1205  			method: "",
  1206  			url: &url.URL{
  1207  				Path: "/user/123",
  1208  			},
  1209  			expected: []attribute.KeyValue{
  1210  				attribute.String("http.method", "GET"),
  1211  				attribute.String("http.url", "/user/123"),
  1212  				attribute.String("http.scheme", "http"),
  1213  			},
  1214  		},
  1215  		{
  1216  			name:   "authentication information is stripped",
  1217  			method: "",
  1218  			url: &url.URL{
  1219  				Path: "/user/123",
  1220  				User: url.UserPassword("foo", "bar"),
  1221  			},
  1222  			expected: []attribute.KeyValue{
  1223  				attribute.String("http.method", "GET"),
  1224  				attribute.String("http.url", "/user/123"),
  1225  				attribute.String("http.scheme", "http"),
  1226  			},
  1227  		},
  1228  	}
  1229  
  1230  	for _, tc := range testCases {
  1231  		t.Run(tc.name, func(t *testing.T) {
  1232  			r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
  1233  			r.ContentLength = tc.contentLength
  1234  			got := sc.HTTPClientAttributesFromHTTPRequest(r)
  1235  			assert.ElementsMatch(t, tc.expected, got)
  1236  		})
  1237  	}
  1238  }
  1239  
  1240  func TestHTTPServerMetricAttributesFromHTTPRequest(t *testing.T) {
  1241  	type testcase struct {
  1242  		name          string
  1243  		serverName    string
  1244  		method        string
  1245  		requestURI    string
  1246  		proto         string
  1247  		remoteAddr    string
  1248  		host          string
  1249  		url           *url.URL
  1250  		header        http.Header
  1251  		tls           tlsOption
  1252  		contentLength int64
  1253  		expected      []attribute.KeyValue
  1254  	}
  1255  	testcases := []testcase{
  1256  		{
  1257  			name:       "stripped",
  1258  			serverName: "",
  1259  			method:     "GET",
  1260  			requestURI: "/user/123",
  1261  			proto:      "HTTP/1.0",
  1262  			remoteAddr: "",
  1263  			host:       "",
  1264  			url: &url.URL{
  1265  				Path: "/user/123",
  1266  			},
  1267  			header: nil,
  1268  			tls:    noTLS,
  1269  			expected: []attribute.KeyValue{
  1270  				attribute.String("http.method", "GET"),
  1271  				attribute.String("http.scheme", "http"),
  1272  				attribute.String("http.flavor", "1.0"),
  1273  			},
  1274  		},
  1275  		{
  1276  			name:       "with server name",
  1277  			serverName: "my-server-name",
  1278  			method:     "GET",
  1279  			requestURI: "/user/123",
  1280  			proto:      "HTTP/1.0",
  1281  			remoteAddr: "",
  1282  			host:       "",
  1283  			url: &url.URL{
  1284  				Path: "/user/123",
  1285  			},
  1286  			header: nil,
  1287  			tls:    noTLS,
  1288  			expected: []attribute.KeyValue{
  1289  				attribute.String("http.method", "GET"),
  1290  				attribute.String("http.scheme", "http"),
  1291  				attribute.String("http.flavor", "1.0"),
  1292  				attribute.String("http.server_name", "my-server-name"),
  1293  			},
  1294  		},
  1295  		{
  1296  			name:       "with tls",
  1297  			serverName: "my-server-name",
  1298  			method:     "GET",
  1299  			requestURI: "/user/123",
  1300  			proto:      "HTTP/1.0",
  1301  			remoteAddr: "",
  1302  			host:       "",
  1303  			url: &url.URL{
  1304  				Path: "/user/123",
  1305  			},
  1306  			header: nil,
  1307  			tls:    withTLS,
  1308  			expected: []attribute.KeyValue{
  1309  				attribute.String("http.method", "GET"),
  1310  				attribute.String("http.scheme", "https"),
  1311  				attribute.String("http.flavor", "1.0"),
  1312  				attribute.String("http.server_name", "my-server-name"),
  1313  			},
  1314  		},
  1315  		{
  1316  			name:       "with route",
  1317  			serverName: "my-server-name",
  1318  			method:     "GET",
  1319  			requestURI: "/user/123",
  1320  			proto:      "HTTP/1.0",
  1321  			remoteAddr: "",
  1322  			host:       "",
  1323  			url: &url.URL{
  1324  				Path: "/user/123",
  1325  			},
  1326  			header: nil,
  1327  			tls:    withTLS,
  1328  			expected: []attribute.KeyValue{
  1329  				attribute.String("http.method", "GET"),
  1330  				attribute.String("http.scheme", "https"),
  1331  				attribute.String("http.flavor", "1.0"),
  1332  				attribute.String("http.server_name", "my-server-name"),
  1333  			},
  1334  		},
  1335  		{
  1336  			name:       "with host",
  1337  			serverName: "my-server-name",
  1338  			method:     "GET",
  1339  			requestURI: "/user/123",
  1340  			proto:      "HTTP/1.0",
  1341  			remoteAddr: "",
  1342  			host:       "example.com",
  1343  			url: &url.URL{
  1344  				Path: "/user/123",
  1345  			},
  1346  			header: nil,
  1347  			tls:    withTLS,
  1348  			expected: []attribute.KeyValue{
  1349  				attribute.String("http.method", "GET"),
  1350  				attribute.String("http.scheme", "https"),
  1351  				attribute.String("http.flavor", "1.0"),
  1352  				attribute.String("http.server_name", "my-server-name"),
  1353  				attribute.String("http.host", "example.com"),
  1354  			},
  1355  		},
  1356  		{
  1357  			name:       "with host fallback",
  1358  			serverName: "my-server-name",
  1359  			method:     "GET",
  1360  			requestURI: "/user/123",
  1361  			proto:      "HTTP/1.0",
  1362  			remoteAddr: "",
  1363  			host:       "",
  1364  			url: &url.URL{
  1365  				Host: "example.com",
  1366  				Path: "/user/123",
  1367  			},
  1368  			header: nil,
  1369  			tls:    withTLS,
  1370  			expected: []attribute.KeyValue{
  1371  				attribute.String("http.method", "GET"),
  1372  				attribute.String("http.scheme", "https"),
  1373  				attribute.String("http.flavor", "1.0"),
  1374  				attribute.String("http.server_name", "my-server-name"),
  1375  				attribute.String("http.host", "example.com"),
  1376  			},
  1377  		},
  1378  		{
  1379  			name:       "with user agent",
  1380  			serverName: "my-server-name",
  1381  			method:     "GET",
  1382  			requestURI: "/user/123",
  1383  			proto:      "HTTP/1.0",
  1384  			remoteAddr: "",
  1385  			host:       "example.com",
  1386  			url: &url.URL{
  1387  				Path: "/user/123",
  1388  			},
  1389  			header: http.Header{
  1390  				"User-Agent": []string{"foodownloader"},
  1391  			},
  1392  			tls: withTLS,
  1393  			expected: []attribute.KeyValue{
  1394  				attribute.String("http.method", "GET"),
  1395  				attribute.String("http.scheme", "https"),
  1396  				attribute.String("http.flavor", "1.0"),
  1397  				attribute.String("http.server_name", "my-server-name"),
  1398  				attribute.String("http.host", "example.com"),
  1399  			},
  1400  		},
  1401  		{
  1402  			name:       "with proxy info",
  1403  			serverName: "my-server-name",
  1404  			method:     "GET",
  1405  			requestURI: "/user/123",
  1406  			proto:      "HTTP/1.0",
  1407  			remoteAddr: "",
  1408  			host:       "example.com",
  1409  			url: &url.URL{
  1410  				Path: "/user/123",
  1411  			},
  1412  			header: http.Header{
  1413  				"User-Agent":      []string{"foodownloader"},
  1414  				"X-Forwarded-For": []string{"203.0.113.195, 70.41.3.18, 150.172.238.178"},
  1415  			},
  1416  			tls: withTLS,
  1417  			expected: []attribute.KeyValue{
  1418  				attribute.String("http.method", "GET"),
  1419  				attribute.String("http.scheme", "https"),
  1420  				attribute.String("http.flavor", "1.0"),
  1421  				attribute.String("http.server_name", "my-server-name"),
  1422  				attribute.String("http.host", "example.com"),
  1423  			},
  1424  		},
  1425  		{
  1426  			name:       "with http 1.1",
  1427  			serverName: "my-server-name",
  1428  			method:     "GET",
  1429  			requestURI: "/user/123",
  1430  			proto:      "HTTP/1.1",
  1431  			remoteAddr: "",
  1432  			host:       "example.com",
  1433  			url: &url.URL{
  1434  				Path: "/user/123",
  1435  			},
  1436  			header: http.Header{
  1437  				"User-Agent":      []string{"foodownloader"},
  1438  				"X-Forwarded-For": []string{"1.2.3.4"},
  1439  			},
  1440  			tls: withTLS,
  1441  			expected: []attribute.KeyValue{
  1442  				attribute.String("http.method", "GET"),
  1443  				attribute.String("http.scheme", "https"),
  1444  				attribute.String("http.flavor", "1.1"),
  1445  				attribute.String("http.server_name", "my-server-name"),
  1446  				attribute.String("http.host", "example.com"),
  1447  			},
  1448  		},
  1449  		{
  1450  			name:       "with http 2",
  1451  			serverName: "my-server-name",
  1452  			method:     "GET",
  1453  			requestURI: "/user/123",
  1454  			proto:      "HTTP/2.0",
  1455  			remoteAddr: "",
  1456  			host:       "example.com",
  1457  			url: &url.URL{
  1458  				Path: "/user/123",
  1459  			},
  1460  			header: http.Header{
  1461  				"User-Agent":      []string{"foodownloader"},
  1462  				"X-Forwarded-For": []string{"1.2.3.4"},
  1463  			},
  1464  			tls: withTLS,
  1465  			expected: []attribute.KeyValue{
  1466  				attribute.String("http.method", "GET"),
  1467  				attribute.String("http.scheme", "https"),
  1468  				attribute.String("http.flavor", "2"),
  1469  				attribute.String("http.server_name", "my-server-name"),
  1470  				attribute.String("http.host", "example.com"),
  1471  			},
  1472  		},
  1473  	}
  1474  	for idx, tc := range testcases {
  1475  		r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
  1476  		r.ContentLength = tc.contentLength
  1477  		got := sc.HTTPServerMetricAttributesFromHTTPRequest(tc.serverName, r)
  1478  		assertElementsMatch(t, tc.expected, got, "testcase %d - %s", idx, tc.name)
  1479  	}
  1480  }
  1481  
  1482  func TestHttpBasicAttributesFromHTTPRequest(t *testing.T) {
  1483  	type testcase struct {
  1484  		name          string
  1485  		method        string
  1486  		requestURI    string
  1487  		proto         string
  1488  		remoteAddr    string
  1489  		host          string
  1490  		url           *url.URL
  1491  		header        http.Header
  1492  		tls           tlsOption
  1493  		contentLength int64
  1494  		expected      []attribute.KeyValue
  1495  	}
  1496  	testcases := []testcase{
  1497  		{
  1498  			name:       "stripped",
  1499  			method:     "GET",
  1500  			requestURI: "/user/123",
  1501  			proto:      "HTTP/1.0",
  1502  			remoteAddr: "",
  1503  			host:       "example.com",
  1504  			url: &url.URL{
  1505  				Path: "/user/123",
  1506  			},
  1507  			header: nil,
  1508  			tls:    noTLS,
  1509  			expected: []attribute.KeyValue{
  1510  				attribute.String("http.method", "GET"),
  1511  				attribute.String("http.scheme", "http"),
  1512  				attribute.String("http.flavor", "1.0"),
  1513  				attribute.String("http.host", "example.com"),
  1514  			},
  1515  		},
  1516  	}
  1517  	for idx, tc := range testcases {
  1518  		r := testRequest(tc.method, tc.requestURI, tc.proto, tc.remoteAddr, tc.host, tc.url, tc.header, tc.tls)
  1519  		r.ContentLength = tc.contentLength
  1520  		got := sc.httpBasicAttributesFromHTTPRequest(r)
  1521  		assertElementsMatch(t, tc.expected, got, "testcase %d - %s", idx, tc.name)
  1522  	}
  1523  }
  1524  

View as plain text