Skip to content
This repository
tree: 81d6136450
Fetching contributors…

Cannot retrieve contributors at this time

file 87 lines (76 sloc) 2.493 kb
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
package falcore

import (
"bytes"
"io"
"net/http"
"strings"
)

// Keeps the body of a request in a string so it can be re-read at each stage of the pipeline
// implements io.ReadCloser to match http.Request.Body

type StringBody struct {
BodyBuffer *bytes.Reader
bpe *bufferPoolEntry
}

type StringBodyFilter struct {
pool *bufferPool
}

func NewStringBodyFilter() *StringBodyFilter {
sbf := &StringBodyFilter{}
sbf.pool = newBufferPool(100, 1024)
return sbf
}
func (sbf *StringBodyFilter) FilterRequest(request *Request) *http.Response {
req := request.HttpRequest
// This caches the request body so that multiple filters can iterate it
if req.Method == "POST" || req.Method == "PUT" {
sb, err := sbf.readRequestBody(req)
if sb == nil || err != nil {
request.CurrentStage.Status = 3 // Skip
Debug("%s No Req Body or Ignored: %v", request.ID, err)
}
} else {
request.CurrentStage.Status = 1 // Skip
}
return nil
}

// reads the request body and replaces the buffer with self
// returns nil if the body is multipart and not replaced
func (sbf *StringBodyFilter) readRequestBody(r *http.Request) (sb *StringBody, err error) {
ct := r.Header.Get("Content-Type")
// leave it on the buffer if we're multipart
if strings.SplitN(ct, ";", 2)[0] != "multipart/form-data" && r.ContentLength > 0 {
sb = &StringBody{}
const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
sb.bpe = sbf.pool.take(io.LimitReader(r.Body, maxFormSize+1))

// There shouldn't be a null byte so we should get EOF
b, e := sb.bpe.br.ReadBytes(0)
if e != nil && e != io.EOF {
return nil, e
}
sb.BodyBuffer = bytes.NewReader(b)
r.Body.Close()
r.Body = sb
return sb, nil
}
return nil, nil // ignore
}

// Returns a buffer used in the FilterRequest stage to a buffer pool
// this speeds up this filter significantly by reusing buffers
func (sbf *StringBodyFilter) ReturnBuffer(request *Request) {
if sb, ok := request.HttpRequest.Body.(*StringBody); ok {
sbf.pool.give(sb.bpe)
}
}

// Insert this in the response pipeline to return the buffer pool for the request body
// If there is an appropriate place in your flow, you can call ReturnBuffer explicitly
func (sbf *StringBodyFilter) FilterResponse(request *Request, res *http.Response) {
sbf.ReturnBuffer(request)
}

func (sb *StringBody) Read(b []byte) (n int, err error) {
return sb.BodyBuffer.Read(b)
}

func (sb *StringBody) Close() error {
// start over
sb.BodyBuffer.Seek(0, 0)
return nil
}
Something went wrong with that request. Please try again.