gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/handlers/logging_test.go (about)

     1  // Copyright 2013 The Gorilla 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 handlers
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/base64"
    10  	"fmt"
    11  	"gitee.com/ks-custle/core-gm/gmhttp/httptest"
    12  	"io/ioutil"
    13  	"math/rand"
    14  	"mime/multipart"
    15  	"net/url"
    16  	"os"
    17  	"path/filepath"
    18  	"strings"
    19  	"testing"
    20  	"time"
    21  
    22  	http "gitee.com/ks-custle/core-gm/gmhttp"
    23  )
    24  
    25  func TestMakeLogger(t *testing.T) {
    26  	rec := httptest.NewRecorder()
    27  	logger, w := makeLogger(rec)
    28  	// initial status
    29  	if logger.Status() != http.StatusOK {
    30  		t.Fatalf("wrong status, got %d want %d", logger.Status(), http.StatusOK)
    31  	}
    32  	// WriteHeader
    33  	w.WriteHeader(http.StatusInternalServerError)
    34  	if logger.Status() != http.StatusInternalServerError {
    35  		t.Fatalf("wrong status, got %d want %d", logger.Status(), http.StatusInternalServerError)
    36  	}
    37  	// Write
    38  	w.Write([]byte(ok))
    39  	if logger.Size() != len(ok) {
    40  		t.Fatalf("wrong size, got %d want %d", logger.Size(), len(ok))
    41  	}
    42  	// Header
    43  	w.Header().Set("key", "value")
    44  	if val := w.Header().Get("key"); val != "value" {
    45  		t.Fatalf("wrong header, got %s want %s", val, "value")
    46  	}
    47  }
    48  
    49  func TestLoggerCleanup(t *testing.T) {
    50  	rand.Seed(time.Now().UnixNano())
    51  
    52  	rbuf := make([]byte, 128)
    53  	if _, err := rand.Read(rbuf); err != nil {
    54  		t.Fatalf("Failed to generate random content: %v", err)
    55  	}
    56  	contents := base64.StdEncoding.EncodeToString(rbuf)
    57  
    58  	var body bytes.Buffer
    59  	body.WriteString(fmt.Sprintf(`
    60  --boundary
    61  Content-Disposition: form-data; name="buzz"; filename="example.txt"
    62  
    63  %s
    64  --boundary--
    65  `, contents))
    66  	r := multipart.NewReader(&body, "boundary")
    67  	form, err := r.ReadForm(0) // small max memory to force flush to disk
    68  	if err != nil {
    69  		t.Fatalf("Failed to read multipart form: %v", err)
    70  	}
    71  
    72  	tmpFiles, err := ioutil.ReadDir(os.TempDir())
    73  	if err != nil {
    74  		t.Fatalf("Failed to list %s: %v", os.TempDir(), err)
    75  	}
    76  
    77  	var tmpFile string
    78  	for _, f := range tmpFiles {
    79  		if !strings.HasPrefix(f.Name(), "multipart-") {
    80  			continue
    81  		}
    82  
    83  		path := filepath.Join(os.TempDir(), f.Name())
    84  		switch b, err := ioutil.ReadFile(path); {
    85  		case err != nil:
    86  			t.Fatalf("Failed to read %s: %v", path, err)
    87  		case string(b) != contents:
    88  			continue
    89  		default:
    90  			tmpFile = path
    91  			break
    92  		}
    93  	}
    94  
    95  	if tmpFile == "" {
    96  		t.Fatal("Could not find multipart form tmp file")
    97  	}
    98  
    99  	req := newRequest("GET", "/subdir/asdf")
   100  	req.MultipartForm = form
   101  
   102  	var buf bytes.Buffer
   103  	handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   104  		req.URL.Path = "/" // simulate http.StripPrefix and friends
   105  		w.WriteHeader(200)
   106  	})
   107  	logger := LoggingHandler(&buf, handler)
   108  	logger.ServeHTTP(httptest.NewRecorder(), req)
   109  
   110  	if _, err := os.Stat(tmpFile); err == nil || !os.IsNotExist(err) {
   111  		t.Fatalf("Expected %s to not exist, got %v", tmpFile, err)
   112  	}
   113  }
   114  
   115  func TestLogPathRewrites(t *testing.T) {
   116  	var buf bytes.Buffer
   117  
   118  	handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   119  		req.URL.Path = "/" // simulate http.StripPrefix and friends
   120  		w.WriteHeader(200)
   121  	})
   122  	logger := LoggingHandler(&buf, handler)
   123  
   124  	logger.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
   125  
   126  	if !strings.Contains(buf.String(), "GET /subdir/asdf HTTP") {
   127  		t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "GET /subdir/asdf HTTP")
   128  	}
   129  }
   130  
   131  func BenchmarkWriteLog(b *testing.B) {
   132  	loc, err := time.LoadLocation("Europe/Warsaw")
   133  	if err != nil {
   134  		b.Fatalf(err.Error())
   135  	}
   136  	ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
   137  
   138  	req := newRequest("GET", "http://example.com")
   139  	req.RemoteAddr = "192.168.100.5"
   140  
   141  	b.ResetTimer()
   142  
   143  	params := LogFormatterParams{
   144  		Request:    req,
   145  		URL:        *req.URL,
   146  		TimeStamp:  ts,
   147  		StatusCode: http.StatusUnauthorized,
   148  		Size:       500,
   149  	}
   150  
   151  	buf := &bytes.Buffer{}
   152  
   153  	for i := 0; i < b.N; i++ {
   154  		buf.Reset()
   155  		writeLog(buf, params)
   156  	}
   157  }
   158  
   159  func TestLogFormatterWriteLog_Scenario1(t *testing.T) {
   160  	formatter := writeLog
   161  	expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100\n"
   162  	LoggingScenario1(t, formatter, expected)
   163  }
   164  
   165  func TestLogFormatterCombinedLog_Scenario1(t *testing.T) {
   166  	formatter := writeCombinedLog
   167  	expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
   168  		"\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
   169  		"AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
   170  	LoggingScenario1(t, formatter, expected)
   171  }
   172  
   173  func TestLogFormatterWriteLog_Scenario2(t *testing.T) {
   174  	formatter := writeLog
   175  	expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"CONNECT www.example.com:443 HTTP/2.0\" 200 100\n"
   176  	LoggingScenario2(t, formatter, expected)
   177  }
   178  
   179  func TestLogFormatterCombinedLog_Scenario2(t *testing.T) {
   180  	formatter := writeCombinedLog
   181  	expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"CONNECT www.example.com:443 HTTP/2.0\" 200 100 \"http://example.com\" " +
   182  		"\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
   183  		"AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
   184  	LoggingScenario2(t, formatter, expected)
   185  }
   186  
   187  func TestLogFormatterWriteLog_Scenario3(t *testing.T) {
   188  	formatter := writeLog
   189  	expected := "192.168.100.5 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 401 500\n"
   190  	LoggingScenario3(t, formatter, expected)
   191  }
   192  
   193  func TestLogFormatterCombinedLog_Scenario3(t *testing.T) {
   194  	formatter := writeCombinedLog
   195  	expected := "192.168.100.5 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 401 500 \"http://example.com\" " +
   196  		"\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
   197  		"AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
   198  	LoggingScenario3(t, formatter, expected)
   199  }
   200  
   201  func TestLogFormatterWriteLog_Scenario4(t *testing.T) {
   202  	formatter := writeLog
   203  	expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET /test?abc=hello%20world&a=b%3F HTTP/1.1\" 200 100\n"
   204  	LoggingScenario4(t, formatter, expected)
   205  }
   206  
   207  func TestLogFormatterCombinedLog_Scenario5(t *testing.T) {
   208  	formatter := writeCombinedLog
   209  	expected := "::1 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
   210  		"\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
   211  		"AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
   212  	LoggingScenario5(t, formatter, expected)
   213  }
   214  
   215  func LoggingScenario1(t *testing.T, formatter LogFormatter, expected string) {
   216  	loc, err := time.LoadLocation("Europe/Warsaw")
   217  	if err != nil {
   218  		panic(err)
   219  	}
   220  	ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
   221  
   222  	// A typical request with an OK response
   223  	req := constructTypicalRequestOk()
   224  
   225  	buf := new(bytes.Buffer)
   226  	params := LogFormatterParams{
   227  		Request:    req,
   228  		URL:        *req.URL,
   229  		TimeStamp:  ts,
   230  		StatusCode: http.StatusOK,
   231  		Size:       100,
   232  	}
   233  
   234  	formatter(buf, params)
   235  	log := buf.String()
   236  
   237  	if log != expected {
   238  		t.Fatalf("wrong log, got %q want %q", log, expected)
   239  	}
   240  }
   241  
   242  func LoggingScenario2(t *testing.T, formatter LogFormatter, expected string) {
   243  	loc, err := time.LoadLocation("Europe/Warsaw")
   244  	if err != nil {
   245  		panic(err)
   246  	}
   247  	ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
   248  
   249  	// CONNECT request over http/2.0
   250  	req := constructConnectRequest()
   251  
   252  	buf := new(bytes.Buffer)
   253  	params := LogFormatterParams{
   254  		Request:    req,
   255  		URL:        *req.URL,
   256  		TimeStamp:  ts,
   257  		StatusCode: http.StatusOK,
   258  		Size:       100,
   259  	}
   260  	formatter(buf, params)
   261  	log := buf.String()
   262  
   263  	if log != expected {
   264  		t.Fatalf("wrong log, got %q want %q", log, expected)
   265  	}
   266  }
   267  
   268  func LoggingScenario3(t *testing.T, formatter LogFormatter, expected string) {
   269  	loc, err := time.LoadLocation("Europe/Warsaw")
   270  	if err != nil {
   271  		panic(err)
   272  	}
   273  	ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
   274  
   275  	// Request with an unauthorized user
   276  	req := constructTypicalRequestOk()
   277  	req.URL.User = url.User("kamil")
   278  
   279  	buf := new(bytes.Buffer)
   280  	params := LogFormatterParams{
   281  		Request:    req,
   282  		URL:        *req.URL,
   283  		TimeStamp:  ts,
   284  		StatusCode: http.StatusUnauthorized,
   285  		Size:       500,
   286  	}
   287  	formatter(buf, params)
   288  	log := buf.String()
   289  
   290  	if log != expected {
   291  		t.Fatalf("wrong log, got %q want %q", log, expected)
   292  	}
   293  }
   294  
   295  func LoggingScenario4(t *testing.T, formatter LogFormatter, expected string) {
   296  	loc, err := time.LoadLocation("Europe/Warsaw")
   297  	if err != nil {
   298  		panic(err)
   299  	}
   300  	ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
   301  
   302  	// Request with url encoded parameters
   303  	req := constructEncodedRequest()
   304  
   305  	buf := new(bytes.Buffer)
   306  	params := LogFormatterParams{
   307  		Request:    req,
   308  		URL:        *req.URL,
   309  		TimeStamp:  ts,
   310  		StatusCode: http.StatusOK,
   311  		Size:       100,
   312  	}
   313  	formatter(buf, params)
   314  	log := buf.String()
   315  
   316  	if log != expected {
   317  		t.Fatalf("wrong log, got %q want %q", log, expected)
   318  	}
   319  }
   320  
   321  func LoggingScenario5(t *testing.T, formatter LogFormatter, expected string) {
   322  	loc, err := time.LoadLocation("Europe/Warsaw")
   323  	if err != nil {
   324  		panic(err)
   325  	}
   326  	ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
   327  
   328  	req := constructTypicalRequestOk()
   329  	req.URL.User = url.User("kamil")
   330  	req.RemoteAddr = "::1"
   331  
   332  	buf := new(bytes.Buffer)
   333  	params := LogFormatterParams{
   334  		Request:    req,
   335  		URL:        *req.URL,
   336  		TimeStamp:  ts,
   337  		StatusCode: http.StatusOK,
   338  		Size:       100,
   339  	}
   340  	formatter(buf, params)
   341  	log := buf.String()
   342  
   343  	if log != expected {
   344  		t.Fatalf("wrong log, got %q want %q", log, expected)
   345  	}
   346  }
   347  
   348  // A typical request with an OK response
   349  func constructTypicalRequestOk() *http.Request {
   350  	req := newRequest("GET", "http://example.com")
   351  	req.RemoteAddr = "192.168.100.5"
   352  	req.Header.Set("Referer", "http://example.com")
   353  	req.Header.Set(
   354  		"User-Agent",
   355  		"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.33 "+
   356  			"(KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33",
   357  	)
   358  	return req
   359  }
   360  
   361  // CONNECT request over http/2.0
   362  func constructConnectRequest() *http.Request {
   363  	req := &http.Request{
   364  		Method:     "CONNECT",
   365  		Host:       "www.example.com:443",
   366  		Proto:      "HTTP/2.0",
   367  		ProtoMajor: 2,
   368  		ProtoMinor: 0,
   369  		RemoteAddr: "192.168.100.5",
   370  		Header:     http.Header{},
   371  		URL:        &url.URL{Host: "www.example.com:443"},
   372  	}
   373  	req.Header.Set("Referer", "http://example.com")
   374  	req.Header.Set(
   375  		"User-Agent",
   376  		"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.33 "+
   377  			"(KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33",
   378  	)
   379  	return req
   380  }
   381  
   382  func constructEncodedRequest() *http.Request {
   383  	req := constructTypicalRequestOk()
   384  	req.URL, _ = url.Parse("http://example.com/test?abc=hello%20world&a=b%3F")
   385  	return req
   386  }