Skip to content

Commit

Permalink
improve statusLine and StatusMessage by using slice instead of map (#…
Browse files Browse the repository at this point in the history
…855)

* 🚀 improve statusLine and StatusMessage by using slice instead of map

Co-authored-by: Fenny <fenny@gofiber.io>
Co-authored-by: ReneWerner87 <rene@gofiber.io>

* for cli stuff

* make invalidStatusLine() just return the formatted line

* for ci stuff

Co-authored-by: Fenny <fenny@gofiber.io>
Co-authored-by: ReneWerner87 <rene@gofiber.io>
  • Loading branch information
3 people authored Aug 2, 2020
1 parent a7c7ef2 commit 2509c12
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 17 deletions.
43 changes: 26 additions & 17 deletions status.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ package fasthttp

import (
"fmt"
"sync/atomic"
)

const (
statusMessageMin = 100
statusMessageMax = 511
)

// HTTP status codes were stolen from net/http.
const (
StatusContinue = 100 // RFC 7231, 6.2.1
StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
StatusProcessing = 102 // RFC 2518, 10.1
StatusEarlyHints = 103 // RFC 8297

StatusOK = 200 // RFC 7231, 6.3.1
StatusCreated = 201 // RFC 7231, 6.3.2
Expand Down Expand Up @@ -51,6 +56,7 @@ const (
StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
StatusExpectationFailed = 417 // RFC 7231, 6.5.14
StatusTeapot = 418 // RFC 7168, 2.3.3
StatusMisdirectedRequest = 421 // RFC 7540, 9.1.2
StatusUnprocessableEntity = 422 // RFC 4918, 11.2
StatusLocked = 423 // RFC 4918, 11.3
StatusFailedDependency = 424 // RFC 4918, 11.4
Expand All @@ -74,12 +80,13 @@ const (
)

var (
statusLines atomic.Value
statusLines = make([][]byte, statusMessageMax+1)

statusMessages = map[int]string{
statusMessages = []string{
StatusContinue: "Continue",
StatusSwitchingProtocols: "Switching Protocols",
StatusProcessing: "Processing",
StatusEarlyHints: "Early Hints",

StatusOK: "OK",
StatusCreated: "Created",
Expand Down Expand Up @@ -120,6 +127,7 @@ var (
StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
StatusExpectationFailed: "Expectation Failed",
StatusTeapot: "I'm a teapot",
StatusMisdirectedRequest: "Misdirected Request",
StatusUnprocessableEntity: "Unprocessable Entity",
StatusLocked: "Locked",
StatusFailedDependency: "Failed Dependency",
Expand All @@ -145,6 +153,10 @@ var (

// StatusMessage returns HTTP status message for the given status code.
func StatusMessage(statusCode int) string {
if statusCode < statusMessageMin || statusCode > statusMessageMax {
return "Unknown Status Code"
}

s := statusMessages[statusCode]
if s == "" {
s = "Unknown Status Code"
Expand All @@ -153,24 +165,21 @@ func StatusMessage(statusCode int) string {
}

func init() {
statusLines.Store(make(map[int][]byte))
// Fill all valid status lines
for i := 0; i < len(statusLines); i++ {
statusLines[i] = []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", i, StatusMessage(i)))
}
}

func statusLine(statusCode int) []byte {
m := statusLines.Load().(map[int][]byte)
h := m[statusCode]
if h != nil {
return h
if statusCode < 0 || statusCode > statusMessageMax {
return invalidStatusLine(statusCode)
}

statusText := StatusMessage(statusCode)
return statusLines[statusCode]
}

h = []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", statusCode, statusText))
newM := make(map[int][]byte, len(m)+1)
for k, v := range m {
newM[k] = v
}
newM[statusCode] = h
statusLines.Store(newM)
return h
func invalidStatusLine(statusCode int) []byte {
statusText := StatusMessage(statusCode)
return []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", statusCode, statusText))
}
24 changes: 24 additions & 0 deletions status_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package fasthttp

import (
"bytes"
"testing"
)

func TestStatusLine(t *testing.T) {
t.Parallel()

testStatusLine(t, -1, []byte("HTTP/1.1 -1 Unknown Status Code\r\n"))
testStatusLine(t, 99, []byte("HTTP/1.1 99 Unknown Status Code\r\n"))
testStatusLine(t, 200, []byte("HTTP/1.1 200 OK\r\n"))
testStatusLine(t, 512, []byte("HTTP/1.1 512 Unknown Status Code\r\n"))
testStatusLine(t, 512, []byte("HTTP/1.1 512 Unknown Status Code\r\n"))
testStatusLine(t, 520, []byte("HTTP/1.1 520 Unknown Status Code\r\n"))
}

func testStatusLine(t *testing.T, statusCode int, expected []byte) {
line := statusLine(statusCode)
if !bytes.Equal(expected, line) {
t.Fatalf("unexpected status line %s. Expecting %s", string(line), string(expected))
}
}
29 changes: 29 additions & 0 deletions status_timing_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package fasthttp

import (
"bytes"
"testing"
)

func BenchmarkStatusLine99(b *testing.B) {
benchmarkStatusLine(b, 99, []byte("HTTP/1.1 99 Unknown Status Code\r\n"))
}

func BenchmarkStatusLine200(b *testing.B) {
benchmarkStatusLine(b, 200, []byte("HTTP/1.1 200 OK\r\n"))
}

func BenchmarkStatusLine512(b *testing.B) {
benchmarkStatusLine(b, 512, []byte("HTTP/1.1 512 Unknown Status Code\r\n"))
}

func benchmarkStatusLine(b *testing.B, statusCode int, expected []byte) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
line := statusLine(statusCode)
if !bytes.Equal(expected, line) {
b.Fatalf("unexpected status line %s. Expecting %s", string(line), string(expected))
}
}
})
}

0 comments on commit 2509c12

Please sign in to comment.