-
Notifications
You must be signed in to change notification settings - Fork 15
/
header.go
159 lines (143 loc) · 3.57 KB
/
header.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Package goexpress header handles the Response & Request Header
// The package is responsible for setting Response headers
// and pushing the same on the transport buffer
package goexpress
import (
"bufio"
"fmt"
"log"
"net/http"
"strconv"
)
// header Struct defines HTTP request/response struct
type header struct {
response http.ResponseWriter
request *http.Request
writer *bufio.ReadWriter
bodySent bool
basicSent bool
hasLength bool
StatusCode int
ProtoMajor int
ProtoMinor int
}
var statusCodeMap = map[int]string{
200: "OK",
201: "Created",
202: "Accepted",
204: "No Content",
205: "Reset Content",
206: "Partial Content",
301: "Moved Permanently",
302: "Found",
304: "Not Modified",
305: "Use Proxy",
306: "Switch Proxy",
307: "Temporary Redirect",
308: "Permanent Redirect",
400: "Bad Request",
401: "Unauthorized",
403: "Forbidden",
404: "NOT FOUND",
405: "Method Not Allowed",
413: "Payload Too Large",
414: "URI Too Long",
500: "Internal Server Error",
501: "Not Implemented",
502: "Bad Gateway",
503: "Service Unavailaible",
504: "Gateway Timeout",
505: "HTTP Version Not Supported",
}
// newHeader initialise with response, request and io buffer
func newHeader(response http.ResponseWriter, request *http.Request, writer *bufio.ReadWriter) *header {
h := &header{}
h.response = response
h.request = request
h.writer = writer
h.bodySent = false
h.basicSent = false
h.ProtoMinor = 1
h.ProtoMajor = 1
return h
}
// Set a header
func (h *header) Set(key string, value string) Header {
h.response.Header().Set(key, value)
return h
}
// Get returns the header
func (h *header) Get(key string) string {
return h.response.Header().Get(key)
}
// GetRequestHeader returns a request header
func (h *header) GetRequestHeader(key string) []string {
return h.request.Header[key]
}
// Del deletes a Header
func (h *header) Del(key string) Header {
h.response.Header().Del(key)
return h
}
// SetLength sets length
// TODO: Add non-chunk response functionality
func (h *header) SetLength(length *int) {
h.response.Header().Set("Content-Length", strconv.Itoa(*length))
h.hasLength = true
}
// FlushHeaders flushes Headers
func (h *header) FlushHeaders() bool {
if h.bodySent == true {
log.Panic("Cannot send headers in middle of body")
return false
}
if h.basicSent == false {
h.sendBasics()
}
// write the latest headers
if h.Get("Content-Type") == "" {
h.Set("Content-Type", "text/html;charset=utf-8")
}
if err := h.response.Header().Write(h.writer); err != nil {
return false
}
var chunkSize = fmt.Sprintf("%x", 0)
h.writer.WriteString(chunkSize + "\r\n" + "\r\n")
h.writer.Writer.Flush()
return true
}
// AppendCookie is an internal helper function to set Cookie Header
func (h *header) AppendCookie(key string, value string) {
if h.Get(key) != "" {
h.Set(key, h.Get(key)+";"+value)
} else {
h.Set(key, value)
}
}
// BasicSent returns the state of Headers whether they are sent or not
func (h *header) BasicSent() bool {
return h.basicSent
}
// CanSendHeader returns the state of response
func (h *header) CanSendHeader() bool {
if h.basicSent == true {
if h.bodySent == false {
return true
}
return false
}
return true
}
// SetStatus sets the HTTP Status of the Request
func (h *header) SetStatus(code int) {
h.StatusCode = code
}
func (h *header) sendBasics() {
if h.StatusCode == 0 {
h.StatusCode = 200
}
fmt.Fprintf(h.writer, "HTTP/%d.%d %03d %s\r\n", h.ProtoMajor, h.ProtoMinor, h.StatusCode, statusCodeMap[h.StatusCode])
h.Set("transfer-encoding", "chunked")
h.Set("connection", "keep-alive")
h.basicSent = true
}