Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 27d7084

Browse filesBrowse files
committed
Revamped engine to reduce the interface size.
Added BufferedServerHeader to CompressWriter to prevent header from writing out immediately Reduced object stack to a single controller stack which has the request and response objects already instaniated in it Fixed go engine to match new spec Modified code to make use of the Request object to access the ServerEngine (allows caching of ServerHeader and ResponseWriter) Modified simple stack to add an upper bounds to the number of objects in cache, any more objects then the upper bounds will be left to garbage collect
1 parent 0019da7 commit 27d7084
Copy full SHA for 27d7084
Expand file treeCollapse file tree

18 files changed

+713
-402
lines changed

‎compress.go

Copy file name to clipboardExpand all lines: compress.go
+110-13Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type WriteFlusher interface {
4040
}
4141

4242
type CompressResponseWriter struct {
43-
Header ServerHeader
43+
Header *BufferedServerHeader
4444
ControllerResponse *Response
4545
OriginalWriter io.Writer
4646
compressWriter WriteFlusher
@@ -51,19 +51,27 @@ type CompressResponseWriter struct {
5151
closed bool
5252
}
5353

54-
// CompressFilter does compresssion of response body in gzip/deflate if
54+
// CompressFilter does compression of response body in gzip/deflate if
5555
// `results.compressed=true` in the app.conf
5656
func CompressFilter(c *Controller, fc []Filter) {
57-
if Config.BoolDefault("results.compressed", false) {
57+
if c.Response.ServerHeader!=nil && Config.BoolDefault("results.compressed", false) {
5858
if c.Response.Status != http.StatusNoContent && c.Response.Status != http.StatusNotModified {
5959
if found, compressType, compressWriter := detectCompressionType(c.Request, c.Response); found {
60-
writer := CompressResponseWriter{c.Response.Out.Header(), c.Response, c.Response.Out.GetWriter(), compressWriter, compressType, false, make(chan bool, 1), nil, false}
61-
if w, ok := c.Response.Out.(http.CloseNotifier); ok {
60+
writer := CompressResponseWriter{
61+
ControllerResponse:c.Response,
62+
OriginalWriter: c.Response.GetWriter(),
63+
compressWriter: compressWriter,
64+
compressionType:compressType,
65+
headersWritten:false,
66+
closeNotify: make(chan bool, 1),
67+
closed: false}
68+
// Swap out the header with our own
69+
writer.Header = NewBufferedServerHeader(c.Response.ServerHeader)
70+
c.Response.ServerHeader = writer.Header
71+
if w, ok := c.Response.GetWriter().(http.CloseNotifier); ok {
6272
writer.parentNotify = w.CloseNotify()
6373
}
64-
c.Response.Out.SetWriter(&writer)
65-
// Block the results from writing there own header
66-
c.Response.headerWritten = true
74+
c.Response.SetWriter(&writer)
6775
}
6876
} else {
6977
TRACE.Printf("Compression disabled for response status (%d)", c.Response.Status)
@@ -101,6 +109,7 @@ func (c *CompressResponseWriter) prepareHeaders() {
101109
c.compressionType = ""
102110
}
103111
}
112+
c.Header.Release()
104113
}
105114

106115
func (c *CompressResponseWriter) WriteHeader(status int) {
@@ -110,12 +119,16 @@ func (c *CompressResponseWriter) WriteHeader(status int) {
110119
}
111120

112121
func (c *CompressResponseWriter) Close() error {
113-
if c.compressionType != "" {
122+
if !c.headersWritten {
123+
c.prepareHeaders()
124+
}
125+
if c.compressionType != "" {
114126
c.Header.Del("Content-Length")
115127
if err := c.compressWriter.Close(); err != nil {
116-
// TODO When writing directly to stream
128+
// TODO When writing directly to stream, an error will be generated
117129
ERROR.Println("Error closing compress writer",c.compressionType, err)
118130
}
131+
119132
}
120133
// Non-blocking write to the closenotifier, if we for some reason should
121134
// get called multiple times
@@ -128,6 +141,7 @@ func (c *CompressResponseWriter) Close() error {
128141
}
129142

130143
func (c *CompressResponseWriter) Write(b []byte) (int, error) {
144+
println("*** Write called")
131145
// Abort if parent has been closed
132146
if c.parentNotify != nil {
133147
select {
@@ -140,6 +154,7 @@ func (c *CompressResponseWriter) Write(b []byte) (int, error) {
140154
if c.closed {
141155
return 0, io.ErrClosedPipe
142156
}
157+
143158
if !c.headersWritten {
144159
c.prepareHeaders()
145160
c.headersWritten = true
@@ -154,7 +169,7 @@ func (c *CompressResponseWriter) Write(b []byte) (int, error) {
154169
// from header "Accept-Encoding"
155170
func detectCompressionType(req *Request, resp *Response) (found bool, compressionType string, compressionKind WriteFlusher) {
156171
if Config.BoolDefault("results.compressed", false) {
157-
acceptedEncodings := strings.Split(req.In.GetHeader().Get("Accept-Encoding"), ",")
172+
acceptedEncodings := strings.Split(req.HttpHeaderValue("Accept-Encoding"), ",")
158173

159174
largestQ := 0.0
160175
chosenEncoding := len(compressionTypes)
@@ -223,12 +238,94 @@ func detectCompressionType(req *Request, resp *Response) (found bool, compressio
223238

224239
switch compressionType {
225240
case "gzip":
226-
compressionKind = gzip.NewWriter(resp.Out.GetWriter())
241+
compressionKind = gzip.NewWriter(resp.GetWriter())
227242
found = true
228243
case "deflate":
229-
compressionKind = zlib.NewWriter(resp.Out.GetWriter())
244+
compressionKind = zlib.NewWriter(resp.GetWriter())
230245
found = true
231246
}
232247
}
233248
return
234249
}
250+
251+
252+
// This class will not send content out until the Released is called, from that point on it will act normally
253+
// It implements all the ServerHeader
254+
type BufferedServerHeader struct {
255+
cookieList []string
256+
headerMap map[string][]string
257+
status int
258+
released bool
259+
original ServerHeader
260+
}
261+
func NewBufferedServerHeader(o ServerHeader) *BufferedServerHeader {
262+
return &BufferedServerHeader{original:o,headerMap:map[string][]string{}}
263+
}
264+
func (bsh *BufferedServerHeader) SetCookie(cookie string) {
265+
if bsh.released {
266+
bsh.original.SetCookie(cookie)
267+
} else {
268+
bsh.cookieList = append(bsh.cookieList,cookie)
269+
}
270+
}
271+
func (bsh *BufferedServerHeader) GetCookie(key string) (value ServerCookie, err error) {
272+
return bsh.original.GetCookie(key)
273+
}
274+
func (bsh *BufferedServerHeader) Set(key string, value string){
275+
if bsh.released {
276+
bsh.original.Set(key,value)
277+
} else {
278+
bsh.headerMap[key]=[]string{value}
279+
}
280+
}
281+
func (bsh *BufferedServerHeader) Add(key string, value string) {
282+
if bsh.released {
283+
bsh.original.Set(key,value)
284+
} else {
285+
old := []string{}
286+
if v,found := bsh.headerMap[key];found {
287+
old = v
288+
}
289+
bsh.headerMap[key]=append(old,value)
290+
}
291+
292+
}
293+
func (bsh *BufferedServerHeader) Del(key string){
294+
if bsh.released {
295+
bsh.original.Del(key)
296+
} else {
297+
delete(bsh.headerMap,key)
298+
}
299+
300+
}
301+
func (bsh *BufferedServerHeader) Get(key string) (value string){
302+
if bsh.released {
303+
value = bsh.original.Get(key)
304+
} else {
305+
if v,found := bsh.headerMap[key]; found && len(v)>0{
306+
value = v[0]
307+
} else {
308+
value = bsh.original.Get(key)
309+
}
310+
}
311+
return
312+
}
313+
func (bsh *BufferedServerHeader) SetStatus(statusCode int) {
314+
if bsh.released {
315+
bsh.original.SetStatus(statusCode)
316+
} else {
317+
bsh.status = statusCode
318+
}
319+
}
320+
func (bsh *BufferedServerHeader) Release() {
321+
bsh.released = true
322+
bsh.original.SetStatus(bsh.status)
323+
for k,v := range bsh.headerMap {
324+
for _,r:=range v {
325+
bsh.original.Set(k, r)
326+
}
327+
}
328+
for _,c:=range bsh.cookieList {
329+
bsh.original.SetCookie(c)
330+
}
331+
}

‎controller.go

Copy file name to clipboardExpand all lines: controller.go
+14-14Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,21 @@ type Controller struct {
4242

4343
// NewController returns new controller instance for Request and Response
4444
func NewControllerEmpty() *Controller {
45-
return &Controller{}
45+
return &Controller{Request:NewRequest(nil),Response:NewResponse(nil)}
4646
}
4747

4848
// New controller, creates a new instance wrapping the request and response in it
49-
func NewController(req *Request, resp *Response) *Controller {
49+
func NewController(context ServerContext) *Controller {
5050
c := NewControllerEmpty()
51-
c.SetController(req, resp)
51+
c.SetController(context)
5252
return c
5353
}
5454

5555
// Sets the request and the response for the controller
56-
func (c *Controller) SetController(req *Request, resp *Response) {
56+
func (c *Controller) SetController(context ServerContext) {
5757

58-
c.Request = req
59-
c.Response = resp
58+
c.Request.SetRequest(context.GetRequest())
59+
c.Response.SetResponse(context.GetResponse())
6060
c.Params = new(Params)
6161
c.Args = map[string]interface{}{}
6262
c.ViewArgs = map[string]interface{}{
@@ -81,8 +81,8 @@ func (c *Controller) Destroy() {
8181
cachedControllerMap[c.Name].Push(appController)
8282
c.AppController = nil
8383
}
84-
c.Request = nil
85-
c.Response = nil
84+
c.Request.Destroy()
85+
c.Response.Destroy()
8686
c.Params = nil
8787
c.Args = nil
8888
c.ViewArgs = nil
@@ -109,8 +109,7 @@ func (c *Controller) FlashParams() {
109109
}
110110

111111
func (c *Controller) SetCookie(cookie *http.Cookie) {
112-
c.Response.Out.Header().SetCookie(cookie.String())
113-
112+
c.Response.SetCookie(cookie.String())
114113
}
115114

116115
func (c *Controller) RenderError(err error) Result {
@@ -315,8 +314,6 @@ func (c *Controller) Redirect(val interface{}, args ...interface{}) Result {
315314
func (c *Controller) Stats() map[string]interface{} {
316315
result := CurrentEngine.Stats()
317316
result["revel-controllers"] = controllerStack.String()
318-
result["revel-requests"] = requestStack.String()
319-
result["revel-response"] = responseStack.String()
320317
for key,appStack := range cachedControllerMap {
321318
result["app-" + key] = appStack.String()
322319
}
@@ -348,8 +345,11 @@ func (c *Controller) SetAction(controllerName, methodName string) error {
348345
if _, ok := cachedControllerMap[c.Name]; !ok {
349346
// Create a new stack for this controller
350347
localType := c.Type.Type
351-
cachedControllerMap[c.Name] = NewStackLock(cachedControllerStackSize, func() interface{} {
352-
return reflect.New(localType).Interface()
348+
cachedControllerMap[c.Name] = NewStackLock(
349+
cachedControllerStackSize,
350+
cachedControllerStackMaxSize,
351+
func() interface{} {
352+
return reflect.New(localType).Interface()
353353
})
354354
}
355355
// Instantiate the controller.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.