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