Repository: valyala/fasthttp
Pull request #579 (2019-05-27 15:44:08)

Added headers constants
Used headers lists from [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
P.S.: Not included obsolete or deprecated headers.


Patch:
diff --git a/header.go b/header.go
index 190ac32..85f9809 100644
--- a/header.go
+++ b/header.go
@@ -178,13 +178,13 @@ func (h *RequestHeader) ResetConnectionClose() {
 
 // ConnectionUpgrade returns true if 'Connection: Upgrade' header is set.
 func (h *ResponseHeader) ConnectionUpgrade() bool {
-	return hasHeaderValue(h.Peek("Connection"), strUpgrade)
+	return hasHeaderValue(h.Peek(HeaderConnection), strUpgrade)
 }
 
 // ConnectionUpgrade returns true if 'Connection: Upgrade' header is set.
 func (h *RequestHeader) ConnectionUpgrade() bool {
 	h.parseRawHeaders()
-	return hasHeaderValue(h.Peek("Connection"), strUpgrade)
+	return hasHeaderValue(h.Peek(HeaderConnection), strUpgrade)
 }
 
 // PeekCookie is able to returns cookie by a given key from response.
@@ -845,16 +845,16 @@ func (h *ResponseHeader) DelBytes(key []byte) {
 
 func (h *ResponseHeader) del(key []byte) {
 	switch string(key) {
-	case "Content-Type":
+	case HeaderContentType:
 		h.contentType = h.contentType[:0]
-	case "Server":
+	case HeaderServer:
 		h.server = h.server[:0]
-	case "Set-Cookie":
+	case HeaderSetCookie:
 		h.cookies = h.cookies[:0]
-	case "Content-Length":
+	case HeaderContentLength:
 		h.contentLength = 0
 		h.contentLengthBytes = h.contentLengthBytes[:0]
-	case "Connection":
+	case HeaderConnection:
 		h.connectionClose = false
 	}
 	h.h = delAllArgsBytes(h.h, key)
@@ -877,18 +877,18 @@ func (h *RequestHeader) DelBytes(key []byte) {
 
 func (h *RequestHeader) del(key []byte) {
 	switch string(key) {
-	case "Host":
+	case HeaderHost:
 		h.host = h.host[:0]
-	case "Content-Type":
+	case HeaderContentType:
 		h.contentType = h.contentType[:0]
-	case "User-Agent":
+	case HeaderUserAgent:
 		h.userAgent = h.userAgent[:0]
-	case "Cookie":
+	case HeaderCookie:
 		h.cookies = h.cookies[:0]
-	case "Content-Length":
+	case HeaderContentLength:
 		h.contentLength = 0
 		h.contentLengthBytes = h.contentLengthBytes[:0]
-	case "Connection":
+	case HeaderConnection:
 		h.connectionClose = false
 	}
 	h.h = delAllArgsBytes(h.h, key)
@@ -964,30 +964,30 @@ func (h *ResponseHeader) SetBytesKV(key, value []byte) {
 // key is in canonical form.
 func (h *ResponseHeader) SetCanonical(key, value []byte) {
 	switch string(key) {
-	case "Content-Type":
+	case HeaderContentType:
 		h.SetContentTypeBytes(value)
-	case "Server":
+	case HeaderServer:
 		h.SetServerBytes(value)
-	case "Set-Cookie":
+	case HeaderSetCookie:
 		var kv *argsKV
 		h.cookies, kv = allocArg(h.cookies)
 		kv.key = getCookieKey(kv.key, value)
 		kv.value = append(kv.value[:0], value...)
-	case "Content-Length":
+	case HeaderContentLength:
 		if contentLength, err := parseContentLength(value); err == nil {
 			h.contentLength = contentLength
 			h.contentLengthBytes = append(h.contentLengthBytes[:0], value...)
 		}
-	case "Connection":
+	case HeaderConnection:
 		if bytes.Equal(strClose, value) {
 			h.SetConnectionClose()
 		} else {
 			h.ResetConnectionClose()
 			h.h = setArgBytes(h.h, key, value, argsHasValue)
 		}
-	case "Transfer-Encoding":
+	case HeaderTransferEncoding:
 		// Transfer-Encoding is managed automatically.
-	case "Date":
+	case HeaderDate:
 		// Date is managed automatically.
 	default:
 		h.h = setArgBytes(h.h, key, value, argsHasValue)
@@ -1149,28 +1149,28 @@ func (h *RequestHeader) SetBytesKV(key, value []byte) {
 func (h *RequestHeader) SetCanonical(key, value []byte) {
 	h.parseRawHeaders()
 	switch string(key) {
-	case "Host":
+	case HeaderHost:
 		h.SetHostBytes(value)
-	case "Content-Type":
+	case HeaderContentType:
 		h.SetContentTypeBytes(value)
-	case "User-Agent":
+	case HeaderUserAgent:
 		h.SetUserAgentBytes(value)
-	case "Cookie":
+	case HeaderCookie:
 		h.collectCookies()
 		h.cookies = parseRequestCookies(h.cookies, value)
-	case "Content-Length":
+	case HeaderContentLength:
 		if contentLength, err := parseContentLength(value); err == nil {
 			h.contentLength = contentLength
 			h.contentLengthBytes = append(h.contentLengthBytes[:0], value...)
 		}
-	case "Connection":
+	case HeaderConnection:
 		if bytes.Equal(strClose, value) {
 			h.SetConnectionClose()
 		} else {
 			h.ResetConnectionClose()
 			h.h = setArgBytes(h.h, key, value, argsHasValue)
 		}
-	case "Transfer-Encoding":
+	case HeaderTransferEncoding:
 		// Transfer-Encoding is managed automatically.
 	default:
 		h.h = setArgBytes(h.h, key, value, argsHasValue)
@@ -1217,18 +1217,18 @@ func (h *RequestHeader) PeekBytes(key []byte) []byte {
 
 func (h *ResponseHeader) peek(key []byte) []byte {
 	switch string(key) {
-	case "Content-Type":
+	case HeaderContentType:
 		return h.ContentType()
-	case "Server":
+	case HeaderServer:
 		return h.Server()
-	case "Connection":
+	case HeaderConnection:
 		if h.ConnectionClose() {
 			return strClose
 		}
 		return peekArgBytes(h.h, key)
-	case "Content-Length":
+	case HeaderContentLength:
 		return h.contentLengthBytes
-	case "Set-Cookie":
+	case HeaderSetCookie:
 		return appendResponseCookieBytes(nil, h.cookies)
 	default:
 		return peekArgBytes(h.h, key)
@@ -1238,20 +1238,20 @@ func (h *ResponseHeader) peek(key []byte) []byte {
 func (h *RequestHeader) peek(key []byte) []byte {
 	h.parseRawHeaders()
 	switch string(key) {
-	case "Host":
+	case HeaderHost:
 		return h.Host()
-	case "Content-Type":
+	case HeaderContentType:
 		return h.ContentType()
-	case "User-Agent":
+	case HeaderUserAgent:
 		return h.UserAgent()
-	case "Connection":
+	case HeaderConnection:
 		if h.ConnectionClose() {
 			return strClose
 		}
 		return peekArgBytes(h.h, key)
-	case "Content-Length":
+	case HeaderContentLength:
 		return h.contentLengthBytes
-	case "Cookie":
+	case HeaderCookie:
 		if h.cookiesCollected {
 			return appendRequestCookieBytes(nil, h.cookies)
 		} else {
diff --git a/headers.go b/headers.go
new file mode 100644
index 0000000..7c3b2cb
--- /dev/null
+++ b/headers.go
@@ -0,0 +1,164 @@
+package fasthttp
+
+// Headers
+const (
+	// Authentication
+	HeaderAuthorization      = "Authorization"
+	HeaderProxyAuthenticate  = "Proxy-Authenticate"
+	HeaderProxyAuthorization = "Proxy-Authorization"
+	HeaderWWWAuthenticate    = "WWW-Authenticate"
+
+	// Caching
+	HeaderAge           = "Age"
+	HeaderCacheControl  = "Cache-Control"
+	HeaderClearSiteData = "Clear-Site-Data"
+	HeaderExpires       = "Expires"
+	HeaderPragma        = "Pragma"
+	HeaderWarning       = "Warning"
+
+	// Client hints
+	HeaderAcceptCH         = "Accept-CH"
+	HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
+	HeaderContentDPR       = "Content-DPR"
+	HeaderDPR              = "DPR"
+	HeaderEarlyData        = "Early-Data"
+	HeaderSaveData         = "Save-Data"
+	HeaderViewportWidth    = "Viewport-Width"
+	HeaderWidth            = "Width"
+
+	// Conditionals
+	HeaderETag              = "ETag"
+	HeaderIfMatch           = "If-Match"
+	HeaderIfModifiedSince   = "If-Modified-Since"
+	HeaderIfNoneMatch       = "If-None-Match"
+	HeaderIfUnmodifiedSince = "If-Unmodified-Since"
+	HeaderLastModified      = "Last-Modified"
+	HeaderVary              = "Vary"
+
+	// Connection management
+	HeaderConnection = "Connection"
+	HeaderKeepAlive  = "Keep-Alive"
+
+	// Content negotiation
+	HeaderAccept         = "Accept"
+	HeaderAcceptCharset  = "Accept-Charset"
+	HeaderAcceptEncoding = "Accept-Encoding"
+	HeaderAcceptLanguage = "Accept-Language"
+
+	// Controls
+	HeaderCookie      = "Cookie"
+	HeaderExpect      = "Expect"
+	HeaderMaxForwards = "Max-Forwards"
+	HeaderSetCookie   = "Set-Cookie"
+
+	// CORS
+	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
+	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
+	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
+	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
+	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
+	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
+	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
+	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
+	HeaderOrigin                        = "Origin"
+	HeaderTimingAllowOrigin             = "Timing-Allow-Origin"
+	HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
+
+	// Do Not Track
+	HeaderDNT = "DNT"
+	HeaderTk  = "Tk"
+
+	// Downloads
+	HeaderContentDisposition = "Content-Disposition"
+
+	// Message body information
+	HeaderContentEncoding = "Content-Encoding"
+	HeaderContentLanguage = "Content-Language"
+	HeaderContentLength   = "Content-Length"
+	HeaderContentLocation = "Content-Location"
+	HeaderContentType     = "Content-Type"
+
+	// Proxies
+	HeaderForwarded       = "Forwarded"
+	HeaderVia             = "Via"
+	HeaderXForwardedFor   = "X-Forwarded-For"
+	HeaderXForwardedHost  = "X-Forwarded-Host"
+	HeaderXForwardedProto = "X-Forwarded-Proto"
+
+	// Redirects
+	HeaderLocation = "Location"
+
+	// Request context
+	HeaderFrom           = "From"
+	HeaderHost           = "Host"
+	HeaderReferer        = "Referer"
+	HeaderReferrerPolicy = "Referrer-Policy"
+	HeaderUserAgent      = "User-Agent"
+
+	// Response context
+	HeaderAllow  = "Allow"
+	HeaderServer = "Server"
+
+	// Range requests
+	HeaderAcceptRanges = "Accept-Ranges"
+	HeaderContentRange = "Content-Range"
+	HeaderIfRange      = "If-Range"
+	HeaderRange        = "Range"
+
+	// Security
+	HeaderContentSecurityPolicy           = "Content-Security-Policy"
+	HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
+	HeaderCrossOriginResourcePolicy       = "Cross-Origin-Resource-Policy"
+	HeaderExpectCT                        = "Expect-CT"
+	HeaderFeaturePolicy                   = "Feature-Policy"
+	HeaderPublicKeyPins                   = "Public-Key-Pins"
+	HeaderPublicKeyPinsReportOnly         = "Public-Key-Pins-Report-Only"
+	HeaderStrictTransportSecurity         = "Strict-Transport-Security"
+	HeaderUpgradeInsecureRequests         = "Upgrade-Insecure-Requests"
+	HeaderXContentTypeOptions             = "X-Content-Type-Options"
+	HeaderXDownloadOptions                = "X-Download-Options"
+	HeaderXFrameOptions                   = "X-Frame-Options"
+	HeaderXPoweredBy                      = "X-Powered-By"
+	HeaderXXSSProtection                  = "X-XSS-Protection"
+
+	// Server-sent event
+	HeaderLastEventID = "Last-Event-ID"
+	HeaderNEL         = "NEL"
+	HeaderPingFrom    = "Ping-From"
+	HeaderPingTo      = "Ping-To"
+	HeaderReportTo    = "Report-To"
+
+	// Transfer coding
+	HeaderTE               = "TE"
+	HeaderTrailer          = "Trailer"
+	HeaderTransferEncoding = "Transfer-Encoding"
+
+	// WebSockets
+	HeaderSecWebSocketAccept     = "Sec-WebSocket-Accept"
+	HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions"
+	HeaderSecWebSocketKey        = "Sec-WebSocket-Key"
+	HeaderSecWebSocketProtocol   = "Sec-WebSocket-Protocol"
+	HeaderSecWebSocketVersion    = "Sec-WebSocket-Version"
+
+	// Other
+	HeaderAcceptPatch         = "Accept-Patch"
+	HeaderAcceptPushPolicy    = "Accept-Push-Policy"
+	HeaderAcceptSignature     = "Accept-Signature"
+	HeaderAltSvc              = "Alt-Svc"
+	HeaderDate                = "Date"
+	HeaderIndex               = "Index"
+	HeaderLargeAllocation     = "Large-Allocation"
+	HeaderLink                = "Link"
+	HeaderPushPolicy          = "Push-Policy"
+	HeaderRetryAfter          = "Retry-After"
+	HeaderServerTiming        = "Server-Timing"
+	HeaderSignature           = "Signature"
+	HeaderSignedHeaders       = "Signed-Headers"
+	HeaderSourceMap           = "SourceMap"
+	HeaderUpgrade             = "Upgrade"
+	HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
+	HeaderXPingback           = "X-Pingback"
+	HeaderXRequestedWith      = "X-RequestedWith"
+	HeaderXRobotsTag          = "X-Robots-Tag"
+	HeaderXUACompatible       = "X-UA-Compatible"
+)
diff --git a/http.go b/http.go
index 79241db..ce30f8c 100644
--- a/http.go
+++ b/http.go
@@ -64,6 +64,10 @@ type Response struct {
 	// Copying Header by value is forbidden. Use pointer to Header instead.
 	Header ResponseHeader
 
+	// Flush headers as soon as possible without waiting for first body bytes.
+	// Relevant for bodyStream only.
+	ImmediateHeaderFlush bool
+
 	bodyStream io.Reader
 	w          responseBodyWriter
 	body       *bytebufferpool.ByteBuffer
@@ -870,6 +874,7 @@ func (resp *Response) Reset() {
 	resp.SkipBody = false
 	resp.raddr = nil
 	resp.laddr = nil
+	resp.ImmediateHeaderFlush = false
 }
 
 func (resp *Response) resetSkipHeader() {
@@ -1455,12 +1460,22 @@ func (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) error {
 	}
 	if contentLength >= 0 {
 		if err = resp.Header.Write(w); err == nil && sendBody {
-			err = writeBodyFixedSize(w, resp.bodyStream, int64(contentLength))
+			if resp.ImmediateHeaderFlush {
+				err = w.Flush()
+			}
+			if err == nil {
+				err = writeBodyFixedSize(w, resp.bodyStream, int64(contentLength))
+			}
 		}
 	} else {
 		resp.Header.SetContentLength(-1)
 		if err = resp.Header.Write(w); err == nil && sendBody {
-			err = writeBodyChunked(w, resp.bodyStream)
+			if resp.ImmediateHeaderFlush {
+				err = w.Flush()
+			}
+			if err == nil {
+				err = writeBodyChunked(w, resp.bodyStream)
+			}
 		}
 	}
 	err1 := resp.closeBodyStream()
diff --git a/server.go b/server.go
index 93c7b0e..98a5be8 100644
--- a/server.go
+++ b/server.go
@@ -1008,6 +1008,8 @@ func addrToIP(addr net.Addr) net.IP {
 
 // Error sets response status code to the given value and sets response body
 // to the given message.
+//
+// Warning: this will reset the response headers and body already set!
 func (ctx *RequestCtx) Error(msg string, statusCode int) {
 	ctx.Response.Reset()
 	ctx.SetStatusCode(statusCode)
diff --git a/strings.go b/strings.go
index 17e5602..6fef4ea 100644
--- a/strings.go
+++ b/strings.go
@@ -32,26 +32,26 @@ var (
 	strTrace   = []byte(MethodTrace)
 	strPatch   = []byte(MethodPatch)
 
-	strExpect           = []byte("Expect")
-	strConnection       = []byte("Connection")
-	strContentLength    = []byte("Content-Length")
-	strContentType      = []byte("Content-Type")
-	strDate             = []byte("Date")
-	strHost             = []byte("Host")
-	strReferer          = []byte("Referer")
-	strServer           = []byte("Server")
-	strTransferEncoding = []byte("Transfer-Encoding")
-	strContentEncoding  = []byte("Content-Encoding")
-	strAcceptEncoding   = []byte("Accept-Encoding")
-	strUserAgent        = []byte("User-Agent")
-	strCookie           = []byte("Cookie")
-	strSetCookie        = []byte("Set-Cookie")
-	strLocation         = []byte("Location")
-	strIfModifiedSince  = []byte("If-Modified-Since")
-	strLastModified     = []byte("Last-Modified")
-	strAcceptRanges     = []byte("Accept-Ranges")
-	strRange            = []byte("Range")
-	strContentRange     = []byte("Content-Range")
+	strExpect           = []byte(HeaderExpect)
+	strConnection       = []byte(HeaderConnection)
+	strContentLength    = []byte(HeaderContentLength)
+	strContentType      = []byte(HeaderContentType)
+	strDate             = []byte(HeaderDate)
+	strHost             = []byte(HeaderHost)
+	strReferer          = []byte(HeaderReferer)
+	strServer           = []byte(HeaderServer)
+	strTransferEncoding = []byte(HeaderTransferEncoding)
+	strContentEncoding  = []byte(HeaderContentEncoding)
+	strAcceptEncoding   = []byte(HeaderAcceptEncoding)
+	strUserAgent        = []byte(HeaderUserAgent)
+	strCookie           = []byte(HeaderCookie)
+	strSetCookie        = []byte(HeaderSetCookie)
+	strLocation         = []byte(HeaderLocation)
+	strIfModifiedSince  = []byte(HeaderIfModifiedSince)
+	strLastModified     = []byte(HeaderLastModified)
+	strAcceptRanges     = []byte(HeaderAcceptRanges)
+	strRange            = []byte(HeaderRange)
+	strContentRange     = []byte(HeaderContentRange)
 
 	strCookieExpires        = []byte("expires")
 	strCookieDomain         = []byte("domain")


Test patch:
diff --git a/client_timing_test.go b/client_timing_test.go
index 8cc72a2..1a97cd8 100644
--- a/client_timing_test.go
+++ b/client_timing_test.go
@@ -186,7 +186,7 @@ func fasthttpEchoHandler(ctx *RequestCtx) {
 }
 
 func nethttpEchoHandler(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "text/plain")
+	w.Header().Set(HeaderContentType, "text/plain")
 	w.Write([]byte(r.RequestURI))
 }
 
@@ -516,7 +516,7 @@ func BenchmarkNetHTTPClientEndToEndBigResponse10Inmemory(b *testing.B) {
 func benchmarkNetHTTPClientEndToEndBigResponseInmemory(b *testing.B, parallelism int) {
 	bigResponse := createFixedBody(1024 * 1024)
 	h := func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
+		w.Header().Set(HeaderContentType, "text/plain")
 		w.Write(bigResponse)
 	}
 	ln := fasthttputil.NewInmemoryListener()
diff --git a/fasthttpadaptor/adaptor_test.go b/fasthttpadaptor/adaptor_test.go
index 96a1093..452711b 100644
--- a/fasthttpadaptor/adaptor_test.go
+++ b/fasthttpadaptor/adaptor_test.go
@@ -95,7 +95,7 @@ func TestNewFastHTTPHandler(t *testing.T) {
 	req.Header.SetMethod(expectedMethod)
 	req.SetRequestURI(expectedRequestURI)
 	req.Header.SetHost(expectedHost)
-	req.Header.Add("Transfer-Encoding", expectedTransferEncoding)
+	req.Header.Add(fasthttp.HeaderTransferEncoding, expectedTransferEncoding)
 	req.BodyWriter().Write([]byte(expectedBody))
 	for k, v := range expectedHeader {
 		req.Header.Set(k, v)
diff --git a/fs_test.go b/fs_test.go
index 9d56d48..083bdb9 100644
--- a/fs_test.go
+++ b/fs_test.go
@@ -115,7 +115,7 @@ func TestServeFileHead(t *testing.T) {
 		t.Fatalf("unexpected error: %s", err)
 	}
 
-	ce := resp.Header.Peek("Content-Encoding")
+	ce := resp.Header.Peek(HeaderContentEncoding)
 	if len(ce) > 0 {
 		t.Fatalf("Unexpected 'Content-Encoding' %q", ce)
 	}
@@ -190,7 +190,7 @@ func TestServeFileCompressed(t *testing.T) {
 	var ctx RequestCtx
 	var req Request
 	req.SetRequestURI("http://foobar.com/baz")
-	req.Header.Set("Accept-Encoding", "gzip")
+	req.Header.Set(HeaderAcceptEncoding, "gzip")
 	ctx.Init(&req, nil, nil)
 
 	ServeFile(&ctx, "fs.go")
@@ -202,7 +202,7 @@ func TestServeFileCompressed(t *testing.T) {
 		t.Fatalf("unexpected error: %s", err)
 	}
 
-	ce := resp.Header.Peek("Content-Encoding")
+	ce := resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "gzip" {
 		t.Fatalf("Unexpected 'Content-Encoding' %q. Expecting %q", ce, "gzip")
 	}
@@ -224,7 +224,7 @@ func TestServeFileUncompressed(t *testing.T) {
 	var ctx RequestCtx
 	var req Request
 	req.SetRequestURI("http://foobar.com/baz")
-	req.Header.Set("Accept-Encoding", "gzip")
+	req.Header.Set(HeaderAcceptEncoding, "gzip")
 	ctx.Init(&req, nil, nil)
 
 	ServeFileUncompressed(&ctx, "fs.go")
@@ -236,7 +236,7 @@ func TestServeFileUncompressed(t *testing.T) {
 		t.Fatalf("unexpected error: %s", err)
 	}
 
-	ce := resp.Header.Peek("Content-Encoding")
+	ce := resp.Header.Peek(HeaderContentEncoding)
 	if len(ce) > 0 {
 		t.Fatalf("Unexpected 'Content-Encoding' %q", ce)
 	}
@@ -319,7 +319,7 @@ func testFSByteRange(t *testing.T, h RequestHandler, filePath string) {
 	if resp.StatusCode() != StatusPartialContent {
 		t.Fatalf("unexpected status code: %d. Expecting %d. filePath=%q", resp.StatusCode(), StatusPartialContent, filePath)
 	}
-	cr := resp.Header.Peek("Content-Range")
+	cr := resp.Header.Peek(HeaderContentRange)
 
 	expectedCR := fmt.Sprintf("bytes %d-%d/%d", startPos, endPos, fileSize)
 	if string(cr) != expectedCR {
@@ -473,7 +473,7 @@ func testFSCompress(t *testing.T, h RequestHandler, filePath string) {
 	if resp.StatusCode() != StatusOK {
 		t.Fatalf("unexpected status code: %d. Expecting %d. filePath=%q", resp.StatusCode(), StatusOK, filePath)
 	}
-	ce := resp.Header.Peek("Content-Encoding")
+	ce := resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "" {
 		t.Fatalf("unexpected content-encoding %q. Expecting empty string. filePath=%q", ce, filePath)
 	}
@@ -482,7 +482,7 @@ func testFSCompress(t *testing.T, h RequestHandler, filePath string) {
 	// request compressed file
 	ctx.Request.Reset()
 	ctx.Request.SetRequestURI(filePath)
-	ctx.Request.Header.Set("Accept-Encoding", "gzip")
+	ctx.Request.Header.Set(HeaderAcceptEncoding, "gzip")
 	h(&ctx)
 	s = ctx.Response.String()
 	br = bufio.NewReader(bytes.NewBufferString(s))
@@ -492,7 +492,7 @@ func testFSCompress(t *testing.T, h RequestHandler, filePath string) {
 	if resp.StatusCode() != StatusOK {
 		t.Fatalf("unexpected status code: %d. Expecting %d. filePath=%q", resp.StatusCode(), StatusOK, filePath)
 	}
-	ce = resp.Header.Peek("Content-Encoding")
+	ce = resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "gzip" {
 		t.Fatalf("unexpected content-encoding %q. Expecting %q. filePath=%q", ce, "gzip", filePath)
 	}
diff --git a/header_test.go b/header_test.go
index 1ff9ccf..7ec21af 100644
--- a/header_test.go
+++ b/header_test.go
@@ -216,7 +216,7 @@ func TestRequestHeaderSetCookieWithSpecialChars(t *testing.T) {
 	if err := h1.Read(br); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	cookie := h1.Peek("Cookie")
+	cookie := h1.Peek(HeaderCookie)
 	if string(cookie) != "ID&14" {
 		t.Fatalf("unexpected cooke: %q. Expecting %q", cookie, "ID&14")
 	}
@@ -389,9 +389,9 @@ func TestRequestHeaderDel(t *testing.T) {
 	var h RequestHeader
 	h.Set("Foo-Bar", "baz")
 	h.Set("aaa", "bbb")
-	h.Set("Connection", "keep-alive")
+	h.Set(HeaderConnection, "keep-alive")
 	h.Set("Content-Type", "aaa")
-	h.Set("Host", "aaabbb")
+	h.Set(HeaderHost, "aaabbb")
 	h.Set("User-Agent", "asdfas")
 	h.Set("Content-Length", "1123")
 	h.Set("Cookie", "foobar=baz")
@@ -412,27 +412,27 @@ func TestRequestHeaderDel(t *testing.T) {
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Connection")
+	hv = h.Peek(HeaderConnection)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Content-Type")
+	hv = h.Peek(HeaderContentType)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Host")
+	hv = h.Peek(HeaderHost)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("User-Agent")
+	hv = h.Peek(HeaderUserAgent)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Content-Length")
+	hv = h.Peek(HeaderContentLength)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Cookie")
+	hv = h.Peek(HeaderCookie)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
@@ -450,10 +450,10 @@ func TestResponseHeaderDel(t *testing.T) {
 	var h ResponseHeader
 	h.Set("Foo-Bar", "baz")
 	h.Set("aaa", "bbb")
-	h.Set("Connection", "keep-alive")
-	h.Set("Content-Type", "aaa")
-	h.Set("Server", "aaabbb")
-	h.Set("Content-Length", "1123")
+	h.Set(HeaderConnection, "keep-alive")
+	h.Set(HeaderContentType, "aaa")
+	h.Set(HeaderServer, "aaabbb")
+	h.Set(HeaderContentLength, "1123")
 
 	var c Cookie
 	c.SetKey("foo")
@@ -463,7 +463,7 @@ func TestResponseHeaderDel(t *testing.T) {
 	h.Del("foo-bar")
 	h.Del("connection")
 	h.DelBytes([]byte("content-type"))
-	h.Del("Server")
+	h.Del(HeaderServer)
 	h.Del("content-length")
 	h.Del("set-cookie")
 
@@ -475,19 +475,19 @@ func TestResponseHeaderDel(t *testing.T) {
 	if len(hv) > 0 {
 		t.Fatalf("non-zero header value: %q", hv)
 	}
-	hv = h.Peek("Connection")
+	hv = h.Peek(HeaderConnection)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Content-Type")
+	hv = h.Peek(HeaderContentType)
 	if string(hv) != string(defaultContentType) {
 		t.Fatalf("unexpected content-type: %q. Expecting %q", hv, defaultContentType)
 	}
-	hv = h.Peek("Server")
+	hv = h.Peek(HeaderServer)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
-	hv = h.Peek("Content-Length")
+	hv = h.Peek(HeaderContentLength)
 	if len(hv) > 0 {
 		t.Fatalf("non-zero value: %q", hv)
 	}
@@ -727,7 +727,7 @@ func TestRequestHeaderSetByteRange(t *testing.T) {
 func testRequestHeaderSetByteRange(t *testing.T, startPos, endPos int, expectedV string) {
 	var h RequestHeader
 	h.SetByteRange(startPos, endPos)
-	v := h.Peek("Range")
+	v := h.Peek(HeaderRange)
 	if string(v) != expectedV {
 		t.Fatalf("unexpected range: %q. Expecting %q. startPos=%d, endPos=%d", v, expectedV, startPos, endPos)
 	}
@@ -741,7 +741,7 @@ func TestResponseHeaderSetContentRange(t *testing.T) {
 func testResponseHeaderSetContentRange(t *testing.T, startPos, endPos, contentLength int, expectedV string) {
 	var h ResponseHeader
 	h.SetContentRange(startPos, endPos, contentLength)
-	v := h.Peek("Content-Range")
+	v := h.Peek(HeaderContentRange)
 	if string(v) != expectedV {
 		t.Fatalf("unexpected content-range: %q. Expecting %q. startPos=%d, endPos=%d, contentLength=%d",
 			v, expectedV, startPos, endPos, contentLength)
@@ -766,7 +766,7 @@ func TestRequestHeaderHasAcceptEncoding(t *testing.T) {
 
 func testRequestHeaderHasAcceptEncoding(t *testing.T, ae, v string, resultExpected bool) {
 	var h RequestHeader
-	h.Set("Accept-Encoding", ae)
+	h.Set(HeaderAcceptEncoding, ae)
 	result := h.HasAcceptEncoding(v)
 	if result != resultExpected {
 		t.Fatalf("unexpected result in HasAcceptEncoding(%q, %q): %v. Expecting %v", ae, v, result, resultExpected)
@@ -1054,8 +1054,8 @@ func testRequestHeaderHTTPVer(t *testing.T, s string, connectionClose bool) {
 func TestResponseHeaderCopyTo(t *testing.T) {
 	var h ResponseHeader
 
-	h.Set("Set-Cookie", "foo=bar")
-	h.Set("Content-Type", "foobar")
+	h.Set(HeaderSetCookie, "foo=bar")
+	h.Set(HeaderContentType, "foobar")
 	h.Set("AAA-BBB", "aaaa")
 
 	var h1 ResponseHeader
@@ -1063,7 +1063,7 @@ func TestResponseHeaderCopyTo(t *testing.T) {
 	if !bytes.Equal(h1.Peek("Set-cookie"), h.Peek("Set-Cookie")) {
 		t.Fatalf("unexpected cookie %q. Expected %q", h1.Peek("set-cookie"), h.Peek("set-cookie"))
 	}
-	if !bytes.Equal(h1.Peek("Content-Type"), h.Peek("Content-Type")) {
+	if !bytes.Equal(h1.Peek(HeaderContentType), h.Peek(HeaderContentType)) {
 		t.Fatalf("unexpected content-type %q. Expected %q", h1.Peek("content-type"), h.Peek("content-type"))
 	}
 	if !bytes.Equal(h1.Peek("aaa-bbb"), h.Peek("AAA-BBB")) {
@@ -1082,17 +1082,17 @@ func TestResponseHeaderCopyTo(t *testing.T) {
 func TestRequestHeaderCopyTo(t *testing.T) {
 	var h RequestHeader
 
-	h.Set("Cookie", "aa=bb; cc=dd")
-	h.Set("Content-Type", "foobar")
-	h.Set("Host", "aaaa")
+	h.Set(HeaderCookie, "aa=bb; cc=dd")
+	h.Set(HeaderContentType, "foobar")
+	h.Set(HeaderHost, "aaaa")
 	h.Set("aaaxxx", "123")
 
 	var h1 RequestHeader
 	h.CopyTo(&h1)
-	if !bytes.Equal(h1.Peek("cookie"), h.Peek("Cookie")) {
+	if !bytes.Equal(h1.Peek("cookie"), h.Peek(HeaderCookie)) {
 		t.Fatalf("unexpected cookie after copying: %q. Expected %q", h1.Peek("cookie"), h.Peek("cookie"))
 	}
-	if !bytes.Equal(h1.Peek("content-type"), h.Peek("Content-Type")) {
+	if !bytes.Equal(h1.Peek("content-type"), h.Peek(HeaderContentType)) {
 		t.Fatalf("unexpected content-type %q. Expected %q", h1.Peek("content-type"), h.Peek("content-type"))
 	}
 	if !bytes.Equal(h1.Peek("host"), h.Peek("host")) {
@@ -1114,8 +1114,8 @@ func TestRequestHeaderCopyTo(t *testing.T) {
 func TestRequestHeaderConnectionClose(t *testing.T) {
 	var h RequestHeader
 
-	h.Set("Connection", "close")
-	h.Set("Host", "foobar")
+	h.Set(HeaderConnection, "close")
+	h.Set(HeaderHost, "foobar")
 	if !h.ConnectionClose() {
 		t.Fatalf("connection: close not set")
 	}
@@ -1138,7 +1138,7 @@ func TestRequestHeaderConnectionClose(t *testing.T) {
 	if !h1.ConnectionClose() {
 		t.Fatalf("unexpected connection: close value: %v", h1.ConnectionClose())
 	}
-	if string(h1.Peek("Connection")) != "close" {
+	if string(h1.Peek(HeaderConnection)) != "close" {
 		t.Fatalf("unexpected connection value: %q. Expecting %q", h.Peek("Connection"), "close")
 	}
 
@@ -1165,7 +1165,7 @@ func TestResponseHeaderSetCookie(t *testing.T) {
 	var h ResponseHeader
 
 	h.Set("set-cookie", "foo=bar; path=/aa/bb; domain=aaa.com")
-	h.Set("Set-Cookie", "aaaaa=bxx")
+	h.Set(HeaderSetCookie, "aaaaa=bxx")
 
 	var c Cookie
 	c.SetKey("foo")
@@ -1210,17 +1210,17 @@ func TestResponseHeaderVisitAll(t *testing.T) {
 		k := string(key)
 		v := string(value)
 		switch k {
-		case "Content-Length":
+		case HeaderContentLength:
 			if v != string(h.Peek(k)) {
 				t.Fatalf("unexpected content-length: %q. Expecting %q", v, h.Peek(k))
 			}
 			contentLengthCount++
-		case "Content-Type":
+		case HeaderContentType:
 			if v != string(h.Peek(k)) {
 				t.Fatalf("Unexpected content-type: %q. Expected %q", v, h.Peek(k))
 			}
 			contentTypeCount++
-		case "Set-Cookie":
+		case HeaderSetCookie:
 			if cookieCount == 0 && v != "aa=bb; path=/foo/bar" {
 				t.Fatalf("unexpected cookie header: %q. Expected %q", v, "aa=bb; path=/foo/bar")
 			}
@@ -1262,7 +1262,7 @@ func TestRequestHeaderVisitAll(t *testing.T) {
 		k := string(key)
 		v := string(value)
 		switch k {
-		case "Host":
+		case HeaderHost:
 			if v != string(h.Peek(k)) {
 				t.Fatalf("Unexpected host value %q. Expected %q", v, h.Peek(k))
 			}
@@ -1275,7 +1275,7 @@ func TestRequestHeaderVisitAll(t *testing.T) {
 				t.Fatalf("Unexpected value %q. Expected %q", v, "ZZ")
 			}
 			xxCount++
-		case "Cookie":
+		case HeaderCookie:
 			if v != "a=b; c=d" {
 				t.Fatalf("Unexpected cookie %q. Expected %q", v, "a=b; c=d")
 			}
@@ -1309,10 +1309,10 @@ func TestResponseHeaderVisitAllInOrder(t *testing.T) {
 	}
 
 	order := []string{
-		"Content-Type",
-		"Cookie",
-		"Host",
-		"User-Agent",
+		HeaderContentType,
+		HeaderCookie,
+		HeaderHost,
+		HeaderUserAgent,
 	}
 	values := []string{
 		"aa",
@@ -1466,7 +1466,7 @@ func equalCookie(c1, c2 *Cookie) bool {
 func TestRequestHeaderCookie(t *testing.T) {
 	var h RequestHeader
 	h.SetRequestURI("/foobar")
-	h.Set("Host", "foobar.com")
+	h.Set(HeaderHost, "foobar.com")
 
 	h.SetCookie("foo", "bar")
 	h.SetCookie("привет", "мир")
@@ -1525,13 +1525,13 @@ func TestResponseHeaderCookieIssue4(t *testing.T) {
 	c.SetValue("bar")
 	h.SetCookie(c)
 
-	if string(h.Peek("Set-Cookie")) != "foo=bar" {
-		t.Fatalf("Unexpected Set-Cookie header %q. Expected %q", h.Peek("Set-Cookie"), "foo=bar")
+	if string(h.Peek(HeaderSetCookie)) != "foo=bar" {
+		t.Fatalf("Unexpected Set-Cookie header %q. Expected %q", h.Peek(HeaderSetCookie), "foo=bar")
 	}
 	cookieSeen := false
 	h.VisitAll(func(key, value []byte) {
 		switch string(key) {
-		case "Set-Cookie":
+		case HeaderSetCookie:
 			cookieSeen = true
 		}
 	})
@@ -1546,13 +1546,13 @@ func TestResponseHeaderCookieIssue4(t *testing.T) {
 		t.Fatalf("Unexpected cookie value %q. Exepcted %q", c.Value(), "bar")
 	}
 
-	if string(h.Peek("Set-Cookie")) != "foo=bar" {
-		t.Fatalf("Unexpected Set-Cookie header %q. Expected %q", h.Peek("Set-Cookie"), "foo=bar")
+	if string(h.Peek(HeaderSetCookie)) != "foo=bar" {
+		t.Fatalf("Unexpected Set-Cookie header %q. Expected %q", h.Peek(HeaderSetCookie), "foo=bar")
 	}
 	cookieSeen = false
 	h.VisitAll(func(key, value []byte) {
 		switch string(key) {
-		case "Set-Cookie":
+		case HeaderSetCookie:
 			cookieSeen = true
 		}
 	})
@@ -1564,17 +1564,17 @@ func TestResponseHeaderCookieIssue4(t *testing.T) {
 func TestRequestHeaderCookieIssue313(t *testing.T) {
 	var h RequestHeader
 	h.SetRequestURI("/")
-	h.Set("Host", "foobar.com")
+	h.Set(HeaderHost, "foobar.com")
 
 	h.SetCookie("foo", "bar")
 
-	if string(h.Peek("Cookie")) != "foo=bar" {
-		t.Fatalf("Unexpected Cookie header %q. Expected %q", h.Peek("Cookie"), "foo=bar")
+	if string(h.Peek(HeaderCookie)) != "foo=bar" {
+		t.Fatalf("Unexpected Cookie header %q. Expected %q", h.Peek(HeaderCookie), "foo=bar")
 	}
 	cookieSeen := false
 	h.VisitAll(func(key, value []byte) {
 		switch string(key) {
-		case "Cookie":
+		case HeaderCookie:
 			cookieSeen = true
 		}
 	})
@@ -1586,13 +1586,13 @@ func TestRequestHeaderCookieIssue313(t *testing.T) {
 		t.Fatalf("Unexpected cookie value %q. Exepcted %q", h.Cookie("foo"), "bar")
 	}
 
-	if string(h.Peek("Cookie")) != "foo=bar" {
-		t.Fatalf("Unexpected Cookie header %q. Expected %q", h.Peek("Cookie"), "foo=bar")
+	if string(h.Peek(HeaderCookie)) != "foo=bar" {
+		t.Fatalf("Unexpected Cookie header %q. Expected %q", h.Peek(HeaderCookie), "foo=bar")
 	}
 	cookieSeen = false
 	h.VisitAll(func(key, value []byte) {
 		switch string(key) {
-		case "Cookie":
+		case HeaderCookie:
 			cookieSeen = true
 		}
 	})
@@ -1648,13 +1648,13 @@ func TestRequestHeaderSetGet(t *testing.T) {
 	h.Set("connection", "close")
 
 	expectRequestHeaderGet(t, h, "Foo", "bar")
-	expectRequestHeaderGet(t, h, "Host", "12345")
-	expectRequestHeaderGet(t, h, "Content-Type", "aaa/bbb")
-	expectRequestHeaderGet(t, h, "Content-Length", "1234")
+	expectRequestHeaderGet(t, h, HeaderHost, "12345")
+	expectRequestHeaderGet(t, h, HeaderContentType, "aaa/bbb")
+	expectRequestHeaderGet(t, h, HeaderContentLength, "1234")
 	expectRequestHeaderGet(t, h, "USER-AGent", "aaabbb")
-	expectRequestHeaderGet(t, h, "Referer", "axcv")
+	expectRequestHeaderGet(t, h, HeaderReferer, "axcv")
 	expectRequestHeaderGet(t, h, "baz", "xxxxx")
-	expectRequestHeaderGet(t, h, "Transfer-Encoding", "")
+	expectRequestHeaderGet(t, h, HeaderTransferEncoding, "")
 	expectRequestHeaderGet(t, h, "connecTION", "close")
 	if !h.ConnectionClose() {
 		t.Fatalf("unset connection: close")
@@ -1686,13 +1686,13 @@ func TestRequestHeaderSetGet(t *testing.T) {
 
 	expectRequestHeaderGet(t, &h1, "Foo", "bar")
 	expectRequestHeaderGet(t, &h1, "HOST", "12345")
-	expectRequestHeaderGet(t, &h1, "Content-Type", "aaa/bbb")
-	expectRequestHeaderGet(t, &h1, "Content-Length", "1234")
+	expectRequestHeaderGet(t, &h1, HeaderContentType, "aaa/bbb")
+	expectRequestHeaderGet(t, &h1, HeaderContentLength, "1234")
 	expectRequestHeaderGet(t, &h1, "USER-AGent", "aaabbb")
-	expectRequestHeaderGet(t, &h1, "Referer", "axcv")
+	expectRequestHeaderGet(t, &h1, HeaderReferer, "axcv")
 	expectRequestHeaderGet(t, &h1, "baz", "xxxxx")
-	expectRequestHeaderGet(t, &h1, "Transfer-Encoding", "")
-	expectRequestHeaderGet(t, &h1, "Connection", "close")
+	expectRequestHeaderGet(t, &h1, HeaderTransferEncoding, "")
+	expectRequestHeaderGet(t, &h1, HeaderConnection, "close")
 	if !h1.ConnectionClose() {
 		t.Fatalf("unset connection: close")
 	}
@@ -1704,17 +1704,17 @@ func TestResponseHeaderSetGet(t *testing.T) {
 	h.Set("content-type", "aaa/bbb")
 	h.Set("connection", "close")
 	h.Set("content-length", "1234")
-	h.Set("Server", "aaaa")
+	h.Set(HeaderServer, "aaaa")
 	h.Set("baz", "xxxxx")
-	h.Set("Transfer-Encoding", "chunked")
+	h.Set(HeaderTransferEncoding, "chunked")
 
 	expectResponseHeaderGet(t, h, "Foo", "bar")
-	expectResponseHeaderGet(t, h, "Content-Type", "aaa/bbb")
-	expectResponseHeaderGet(t, h, "Connection", "close")
-	expectResponseHeaderGet(t, h, "Content-Length", "1234")
+	expectResponseHeaderGet(t, h, HeaderContentType, "aaa/bbb")
+	expectResponseHeaderGet(t, h, HeaderConnection, "close")
+	expectResponseHeaderGet(t, h, HeaderContentLength, "1234")
 	expectResponseHeaderGet(t, h, "seRVer", "aaaa")
 	expectResponseHeaderGet(t, h, "baz", "xxxxx")
-	expectResponseHeaderGet(t, h, "Transfer-Encoding", "")
+	expectResponseHeaderGet(t, h, HeaderTransferEncoding, "")
 
 	if h.ContentLength() != 1234 {
 		t.Fatalf("Unexpected content-length %d. Expected %d", h.ContentLength(), 1234)
@@ -1747,8 +1747,8 @@ func TestResponseHeaderSetGet(t *testing.T) {
 	}
 
 	expectResponseHeaderGet(t, &h1, "Foo", "bar")
-	expectResponseHeaderGet(t, &h1, "Content-Type", "aaa/bbb")
-	expectResponseHeaderGet(t, &h1, "Connection", "close")
+	expectResponseHeaderGet(t, &h1, HeaderContentType, "aaa/bbb")
+	expectResponseHeaderGet(t, &h1, HeaderConnection, "close")
 	expectResponseHeaderGet(t, &h1, "seRVer", "aaaa")
 	expectResponseHeaderGet(t, &h1, "baz", "xxxxx")
 }
@@ -2280,8 +2280,8 @@ func verifyResponseHeader(t *testing.T, h *ResponseHeader, expectedStatusCode, e
 	if h.ContentLength() != expectedContentLength {
 		t.Fatalf("Unexpected content length %d. Expected %d", h.ContentLength(), expectedContentLength)
 	}
-	if string(h.Peek("Content-Type")) != expectedContentType {
-		t.Fatalf("Unexpected content type %q. Expected %q", h.Peek("Content-Type"), expectedContentType)
+	if string(h.Peek(HeaderContentType)) != expectedContentType {
+		t.Fatalf("Unexpected content type %q. Expected %q", h.Peek(HeaderContentType), expectedContentType)
 	}
 }
 
@@ -2293,14 +2293,14 @@ func verifyRequestHeader(t *testing.T, h *RequestHeader, expectedContentLength i
 	if string(h.RequestURI()) != expectedRequestURI {
 		t.Fatalf("Unexpected RequestURI %q. Expected %q", h.RequestURI(), expectedRequestURI)
 	}
-	if string(h.Peek("Host")) != expectedHost {
-		t.Fatalf("Unexpected host %q. Expected %q", h.Peek("Host"), expectedHost)
+	if string(h.Peek(HeaderHost)) != expectedHost {
+		t.Fatalf("Unexpected host %q. Expected %q", h.Peek(HeaderHost), expectedHost)
 	}
-	if string(h.Peek("Referer")) != expectedReferer {
-		t.Fatalf("Unexpected referer %q. Expected %q", h.Peek("Referer"), expectedReferer)
+	if string(h.Peek(HeaderReferer)) != expectedReferer {
+		t.Fatalf("Unexpected referer %q. Expected %q", h.Peek(HeaderReferer), expectedReferer)
 	}
-	if string(h.Peek("Content-Type")) != expectedContentType {
-		t.Fatalf("Unexpected content-type %q. Expected %q", h.Peek("Content-Type"), expectedContentType)
+	if string(h.Peek(HeaderContentType)) != expectedContentType {
+		t.Fatalf("Unexpected content-type %q. Expected %q", h.Peek(HeaderContentType), expectedContentType)
 	}
 }
 
diff --git a/http_test.go b/http_test.go
index cd31f87..e739a9c 100644
--- a/http_test.go
+++ b/http_test.go
@@ -730,8 +730,8 @@ func TestRequestReadGzippedBody(t *testing.T) {
 		t.Fatalf("unexpected error: %s", err)
 	}
 
-	if string(r.Header.Peek("Content-Encoding")) != "gzip" {
-		t.Fatalf("unexpected content-encoding: %q. Expecting %q", r.Header.Peek("Content-Encoding"), "gzip")
+	if string(r.Header.Peek(HeaderContentEncoding)) != "gzip" {
+		t.Fatalf("unexpected content-encoding: %q. Expecting %q", r.Header.Peek(HeaderContentEncoding), "gzip")
 	}
 	if r.Header.ContentLength() != len(body) {
 		t.Fatalf("unexpected content-length: %d. Expecting %d", r.Header.ContentLength(), len(body))
@@ -913,7 +913,7 @@ func testResponseDeflateExt(t *testing.T, r *Response, s string) {
 		t.Fatalf("unexpected error: %s", err)
 	}
 
-	ce := r1.Header.Peek("Content-Encoding")
+	ce := r1.Header.Peek(HeaderContentEncoding)
 	var body []byte
 	if isCompressible {
 		if string(ce) != "deflate" {
@@ -966,7 +966,7 @@ func testResponseGzipExt(t *testing.T, r *Response, s string) {
 		t.Fatalf("unexpected error: %s", err)
 	}
 
-	ce := r1.Header.Peek("Content-Encoding")
+	ce := r1.Header.Peek(HeaderContentEncoding)
 	var body []byte
 	if isCompressible {
 		if string(ce) != "gzip" {
@@ -1485,11 +1485,11 @@ func testResponseSuccess(t *testing.T, statusCode int, contentType, serverName,
 	if resp1.Header.ContentLength() != len(body) {
 		t.Fatalf("Unexpected content-length: %d. Expected %d", resp1.Header.ContentLength(), len(body))
 	}
-	if string(resp1.Header.Peek("Content-Type")) != expectedContentType {
-		t.Fatalf("Unexpected content-type: %q. Expected %q", resp1.Header.Peek("Content-Type"), expectedContentType)
+	if string(resp1.Header.Peek(HeaderContentType)) != expectedContentType {
+		t.Fatalf("Unexpected content-type: %q. Expected %q", resp1.Header.Peek(HeaderContentType), expectedContentType)
 	}
-	if string(resp1.Header.Peek("Server")) != expectedServerName {
-		t.Fatalf("Unexpected server: %q. Expected %q", resp1.Header.Peek("Server"), expectedServerName)
+	if string(resp1.Header.Peek(HeaderServer)) != expectedServerName {
+		t.Fatalf("Unexpected server: %q. Expected %q", resp1.Header.Peek(HeaderServer), expectedServerName)
 	}
 	if !bytes.Equal(resp1.Body(), []byte(body)) {
 		t.Fatalf("Unexpected body: %q. Expected %q", resp1.Body(), body)
@@ -1509,8 +1509,8 @@ func testRequestWriteError(t *testing.T, method, requestURI, host, userAgent, bo
 
 	req.Header.SetMethod(method)
 	req.Header.SetRequestURI(requestURI)
-	req.Header.Set("Host", host)
-	req.Header.Set("User-Agent", userAgent)
+	req.Header.Set(HeaderHost, host)
+	req.Header.Set(HeaderUserAgent, userAgent)
 	req.SetBody([]byte(body))
 
 	w := &bytebufferpool.ByteBuffer{}
@@ -1526,13 +1526,13 @@ func testRequestSuccess(t *testing.T, method, requestURI, host, userAgent, body,
 
 	req.Header.SetMethod(method)
 	req.Header.SetRequestURI(requestURI)
-	req.Header.Set("Host", host)
-	req.Header.Set("User-Agent", userAgent)
+	req.Header.Set(HeaderHost, host)
+	req.Header.Set(HeaderUserAgent, userAgent)
 	req.SetBody([]byte(body))
 
 	contentType := "foobar"
 	if method == MethodPost {
-		req.Header.Set("Content-Type", contentType)
+		req.Header.Set(HeaderContentType, contentType)
 	}
 
 	w := &bytes.Buffer{}
@@ -1559,18 +1559,18 @@ func testRequestSuccess(t *testing.T, method, requestURI, host, userAgent, body,
 	if string(req1.Header.RequestURI()) != requestURI {
 		t.Fatalf("Unexpected RequestURI: %q. Expected %q", req1.Header.RequestURI(), requestURI)
 	}
-	if string(req1.Header.Peek("Host")) != host {
-		t.Fatalf("Unexpected host: %q. Expected %q", req1.Header.Peek("Host"), host)
+	if string(req1.Header.Peek(HeaderHost)) != host {
+		t.Fatalf("Unexpected host: %q. Expected %q", req1.Header.Peek(HeaderHost), host)
 	}
-	if string(req1.Header.Peek("User-Agent")) != userAgent {
-		t.Fatalf("Unexpected user-agent: %q. Expected %q", req1.Header.Peek("User-Agent"), userAgent)
+	if string(req1.Header.Peek(HeaderUserAgent)) != userAgent {
+		t.Fatalf("Unexpected user-agent: %q. Expected %q", req1.Header.Peek(HeaderUserAgent), userAgent)
 	}
 	if !bytes.Equal(req1.Body(), []byte(body)) {
 		t.Fatalf("Unexpected body: %q. Expected %q", req1.Body(), body)
 	}
 
-	if method == MethodPost && string(req1.Header.Peek("Content-Type")) != contentType {
-		t.Fatalf("Unexpected content-type: %q. Expected %q", req1.Header.Peek("Content-Type"), contentType)
+	if method == MethodPost && string(req1.Header.Peek(HeaderContentType)) != contentType {
+		t.Fatalf("Unexpected content-type: %q. Expected %q", req1.Header.Peek(HeaderContentType), contentType)
 	}
 }
 
@@ -1729,7 +1729,7 @@ func TestRequestURI(t *testing.T) {
 	expectedHash := "1334dfds&=d"
 
 	var req Request
-	req.Header.Set("Host", host)
+	req.Header.Set(HeaderHost, host)
 	req.Header.SetRequestURI(requestURI)
 
 	uri := req.URI()
@@ -1921,3 +1921,133 @@ func TestResponseRawBodyCopyTo(t *testing.T) {
 
 	testResponseCopyTo(t, &resp)
 }
+
+type testReader struct {
+	read chan (int)
+	cb   chan (struct{})
+}
+
+func (r *testReader) Read(b []byte) (int, error) {
+	read := <-r.read
+
+	if read == -1 {
+		return 0, io.EOF
+	}
+
+	r.cb <- struct{}{}
+
+	for i := 0; i < read; i++ {
+		b[i] = 'x'
+	}
+
+	return read, nil
+}
+
+func TestResponseImmediateHeaderFlushRegressionFixedLength(t *testing.T) {
+	var r Response
+
+	expectedS := "aaabbbccc"
+	buf := bytes.NewBufferString(expectedS)
+	r.SetBodyStream(buf, len(expectedS))
+	r.ImmediateHeaderFlush = true
+
+	testBodyWriteTo(t, &r, expectedS, false)
+}
+
+func TestResponseImmediateHeaderFlushRegressionChunked(t *testing.T) {
+	var r Response
+
+	expectedS := "aaabbbccc"
+	buf := bytes.NewBufferString(expectedS)
+	r.SetBodyStream(buf, -1)
+	r.ImmediateHeaderFlush = true
+
+	testBodyWriteTo(t, &r, expectedS, false)
+}
+
+func TestResponseImmediateHeaderFlushFixedLength(t *testing.T) {
+	var r Response
+
+	r.ImmediateHeaderFlush = true
+
+	ch := make(chan int)
+	cb := make(chan struct{})
+
+	buf := &testReader{read: ch, cb: cb}
+
+	r.SetBodyStream(buf, 3)
+
+	b := []byte{}
+	w := bytes.NewBuffer(b)
+	bb := bufio.NewWriter(w)
+
+	bw := &r
+
+	waitForIt := make(chan struct{})
+
+	go func() {
+		if err := bw.Write(bb); err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		waitForIt <- struct{}{}
+	}()
+
+	ch <- 3
+
+	if !strings.Contains(w.String(), "Content-Length: 3") {
+		t.Fatalf("Expected headers to be flushed")
+	}
+
+	if strings.Contains(w.String(), "xxx") {
+		t.Fatalf("Did not expext body to be written yet")
+	}
+
+	<-cb
+	ch <- -1
+
+	<-waitForIt
+}
+
+func TestResponseImmediateHeaderFlushChunked(t *testing.T) {
+	var r Response
+
+	r.ImmediateHeaderFlush = true
+
+	ch := make(chan int)
+	cb := make(chan struct{})
+
+	buf := &testReader{read: ch, cb: cb}
+
+	r.SetBodyStream(buf, -1)
+
+	b := []byte{}
+	w := bytes.NewBuffer(b)
+	bb := bufio.NewWriter(w)
+
+	bw := &r
+
+	waitForIt := make(chan struct{})
+
+	go func() {
+		if err := bw.Write(bb); err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+
+		waitForIt <- struct{}{}
+	}()
+
+	ch <- 3
+
+	if !strings.Contains(w.String(), "Transfer-Encoding: chunked") {
+		t.Fatalf("Expected headers to be flushed")
+	}
+
+	if strings.Contains(w.String(), "xxx") {
+		t.Fatalf("Did not expext body to be written yet")
+	}
+
+	<-cb
+	ch <- -1
+
+	<-waitForIt
+}
diff --git a/server_test.go b/server_test.go
index 8d7d97f..a68d432 100644
--- a/server_test.go
+++ b/server_test.go
@@ -314,7 +314,7 @@ func TestRequestCtxRedirectHTTPSSchemeless(t *testing.T) {
 	ctx.Request.isTLS = true
 
 	ctx.Redirect("//foobar.com/aa/bbb", StatusFound)
-	location := ctx.Response.Header.Peek("Location")
+	location := ctx.Response.Header.Peek(HeaderLocation)
 	expectedLocation := "https://foobar.com/aa/bbb"
 	if string(location) != expectedLocation {
 		t.Fatalf("Unexpected location: %q. Expecting %q", location, expectedLocation)
@@ -348,7 +348,7 @@ func testRequestCtxRedirect(t *testing.T, origURL, redirectURL, expectedURL stri
 	ctx.Init(&req, nil, nil)
 
 	ctx.Redirect(redirectURL, StatusFound)
-	loc := ctx.Response.Header.Peek("Location")
+	loc := ctx.Response.Header.Peek(HeaderLocation)
 	if string(loc) != expectedURL {
 		t.Fatalf("unexpected redirect url %q. Expecting %q. origURL=%q, redirectURL=%q", loc, expectedURL, origURL, redirectURL)
 	}
@@ -1005,7 +1005,7 @@ Connection: close
 		if resp.StatusCode() != StatusSeeOther {
 			t.Fatalf("unexpected status code %d. Expecting %d", resp.StatusCode(), StatusSeeOther)
 		}
-		loc := resp.Header.Peek("Location")
+		loc := resp.Header.Peek(HeaderLocation)
 		if string(loc) != "http://qwerty.com/" {
 			t.Fatalf("unexpected location %q. Expecting %q", loc, "http://qwerty.com/")
 		}
@@ -1317,9 +1317,9 @@ func TestServerHTTP10ConnectionClose(t *testing.T) {
 			// handler, since the HTTP/1.0 request
 			// had no 'Connection: keep-alive' header.
 			ctx.Request.Header.ResetConnectionClose()
-			ctx.Request.Header.Set("Connection", "keep-alive")
+			ctx.Request.Header.Set(HeaderConnection, "keep-alive")
 			ctx.Response.Header.ResetConnectionClose()
-			ctx.Response.Header.Set("Connection", "keep-alive")
+			ctx.Response.Header.Set(HeaderConnection, "keep-alive")
 		})
 		if err != nil {
 			t.Fatalf("unexpected error: %s", err)
@@ -1553,7 +1553,7 @@ func TestCompressHandler(t *testing.T) {
 	if err := resp.Read(br); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	ce := resp.Header.Peek("Content-Encoding")
+	ce := resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "" {
 		t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "")
 	}
@@ -1573,7 +1573,7 @@ func TestCompressHandler(t *testing.T) {
 	if err := resp.Read(br); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	ce = resp.Header.Peek("Content-Encoding")
+	ce = resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "gzip" {
 		t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "gzip")
 	}
@@ -1596,7 +1596,7 @@ func TestCompressHandler(t *testing.T) {
 	if err := resp.Read(br); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	ce = resp.Header.Peek("Content-Encoding")
+	ce = resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "gzip" {
 		t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "gzip")
 	}
@@ -1611,7 +1611,7 @@ func TestCompressHandler(t *testing.T) {
 	// verify deflate-compressed response
 	ctx.Request.Reset()
 	ctx.Response.Reset()
-	ctx.Request.Header.Set("Accept-Encoding", "foobar, deflate, sdhc")
+	ctx.Request.Header.Set(HeaderAcceptEncoding, "foobar, deflate, sdhc")
 
 	h(&ctx)
 	s = ctx.Response.String()
@@ -1619,7 +1619,7 @@ func TestCompressHandler(t *testing.T) {
 	if err := resp.Read(br); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	ce = resp.Header.Peek("Content-Encoding")
+	ce = resp.Header.Peek(HeaderContentEncoding)
 	if string(ce) != "deflate" {
 		t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "deflate")
 	}
@@ -1689,8 +1689,8 @@ func TestServeConnNonHTTP11KeepAlive(t *testing.T) {
 	if err := resp.Read(br); err != nil {
 		t.Fatalf("Unexpected error when parsing response: %s", err)
 	}
-	if string(resp.Header.Peek("Connection")) != "keep-alive" {
-		t.Fatalf("unexpected Connection header %q. Expecting %q", resp.Header.Peek("Connection"), "keep-alive")
+	if string(resp.Header.Peek(HeaderConnection)) != "keep-alive" {
+		t.Fatalf("unexpected Connection header %q. Expecting %q", resp.Header.Peek(HeaderConnection), "keep-alive")
 	}
 	if resp.Header.ConnectionClose() {
 		t.Fatalf("unexpected Connection: close")
@@ -1700,8 +1700,8 @@ func TestServeConnNonHTTP11KeepAlive(t *testing.T) {
 	if err := resp.Read(br); err != nil {
 		t.Fatalf("Unexpected error when parsing response: %s", err)
 	}
-	if string(resp.Header.Peek("Connection")) != "close" {
-		t.Fatalf("unexpected Connection header %q. Expecting %q", resp.Header.Peek("Connection"), "close")
+	if string(resp.Header.Peek(HeaderConnection)) != "close" {
+		t.Fatalf("unexpected Connection header %q. Expecting %q", resp.Header.Peek(HeaderConnection), "close")
 	}
 	if !resp.Header.ConnectionClose() {
 		t.Fatalf("expecting Connection: close")
@@ -2608,8 +2608,8 @@ func TestServerConnError(t *testing.T) {
 	if resp.Header.ContentLength() != 6 {
 		t.Fatalf("Unexpected Content-Length %d. Expected %d", resp.Header.ContentLength(), 6)
 	}
-	if !bytes.Equal(resp.Header.Peek("Content-Type"), defaultContentType) {
-		t.Fatalf("Unexpected Content-Type %q. Expected %q", resp.Header.Peek("Content-Type"), defaultContentType)
+	if !bytes.Equal(resp.Header.Peek(HeaderContentType), defaultContentType) {
+		t.Fatalf("Unexpected Content-Type %q. Expected %q", resp.Header.Peek(HeaderContentType), defaultContentType)
 	}
 	if !bytes.Equal(resp.Body(), []byte("foobar")) {
 		t.Fatalf("Unexpected body %q. Expected %q", resp.Body(), "foobar")
@@ -2620,7 +2620,7 @@ func TestServeConnSingleRequest(t *testing.T) {
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
 			h := &ctx.Request.Header
-			ctx.Success("aaa", []byte(fmt.Sprintf("requestURI=%s, host=%s", h.RequestURI(), h.Peek("Host"))))
+			ctx.Success("aaa", []byte(fmt.Sprintf("requestURI=%s, host=%s", h.RequestURI(), h.Peek(HeaderHost))))
 		},
 	}
 
@@ -2649,7 +2649,7 @@ func TestServeConnMultiRequests(t *testing.T) {
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
 			h := &ctx.Request.Header
-			ctx.Success("aaa", []byte(fmt.Sprintf("requestURI=%s, host=%s", h.RequestURI(), h.Peek("Host"))))
+			ctx.Success("aaa", []byte(fmt.Sprintf("requestURI=%s, host=%s", h.RequestURI(), h.Peek(HeaderHost))))
 		},
 	}
 
diff --git a/server_timing_test.go b/server_timing_test.go
index e4318a7..d8893f6 100644
--- a/server_timing_test.go
+++ b/server_timing_test.go
@@ -353,7 +353,7 @@ func benchmarkNetHTTPServerGet(b *testing.B, clientsCount, requestsPerConn int)
 			h := w.Header()
 			h.Set("Content-Type", "text/plain")
 			if requestsPerConn == 1 {
-				h.Set("Connection", "close")
+				h.Set(HeaderConnection, "close")
 			}
 			w.Write(fakeResponse)
 			registerServedRequest(b, ch)
@@ -404,7 +404,7 @@ func benchmarkNetHTTPServerPost(b *testing.B, clientsCount, requestsPerConn int)
 			h := w.Header()
 			h.Set("Content-Type", "text/plain")
 			if requestsPerConn == 1 {
-				h.Set("Connection", "close")
+				h.Set(HeaderConnection, "close")
 			}
 			w.Write(body)
 			registerServedRequest(b, ch)