Skip to content

Commit

Permalink
Merge pull request #157 from buger/encoding-chunked
Browse files Browse the repository at this point in the history
Handle Transfer-Encoding: chunked
  • Loading branch information
buger committed Jun 26, 2015
2 parents a059648 + 534e9b2 commit 6fe7ba8
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 5 deletions.
18 changes: 16 additions & 2 deletions output_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"sync/atomic"
Expand All @@ -29,18 +30,31 @@ func (o *HTTPOutput) customCheckRedirect(req *http.Request, via []*http.Request)

// ParseRequest in []byte returns a http request or an error
func ParseRequest(data []byte) (request *http.Request, err error) {
var body []byte

// Test if request have Transfer-Encoding: chunked
isChunked := bytes.Contains(data, []byte(": chunked\r\n"))

buf := bytes.NewBuffer(data)
reader := bufio.NewReader(buf)

// ReadRequest does not read POST bodies, we have to do it by ourseves
request, err = http.ReadRequest(reader)

if err != nil {
return
}

if request.Method == "POST" {
body, _ := ioutil.ReadAll(reader)
// This works, because ReadRequest method modify buffer and strips all headers, leaving only body
if isChunked {
body, _ = ioutil.ReadAll(httputil.NewChunkedReader(reader))
} else {
body, _ = ioutil.ReadAll(reader)
}

bodyBuf := bytes.NewBuffer(body)

request.Body = ioutil.NopCloser(bodyBuf)
request.ContentLength = int64(bodyBuf.Len())
}
Expand All @@ -62,7 +76,7 @@ type HTTPOutput struct {

redirectLimit int

needWorker chan int
needWorker chan int

urlRegexp HTTPUrlRegexp
headerFilters HTTPHeaderFilters
Expand Down
38 changes: 37 additions & 1 deletion output_http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestHTTPOutput(t *testing.T) {
defer req.Body.Close()
body, _ := ioutil.ReadAll(req.Body)

if string(body) != "a=1&b=2\r\n\r\n" {
if string(body) != "a=1&b=2" {
buf, _ := httputil.DumpRequest(req, true)
t.Error("Wrong POST body:", string(buf))
}
Expand Down Expand Up @@ -95,6 +95,42 @@ func TestHTTPOutput(t *testing.T) {
close(quit)
}

func TestHTTPOutputChunkedEncoding(t *testing.T) {
wg := new(sync.WaitGroup)
quit := make(chan int)

input := NewTestInput()

headers := HTTPHeaders{HTTPHeader{"User-Agent", "Gor"}}
methods := HTTPMethods{"GET", "PUT", "POST"}

listener := startHTTP(func(req *http.Request) {
defer req.Body.Close()
body, _ := ioutil.ReadAll(req.Body)

if string(body) != "Wikipedia in\r\n\r\nchunks." {
buf, _ := httputil.DumpRequest(req, true)
t.Error("Wrong POST body:", buf, body, []byte("Wikipedia in\r\n\r\nchunks."))
}

wg.Done()
})

output := NewHTTPOutput(listener.Addr().String(), headers, methods, HTTPUrlRegexp{}, HTTPHeaderFilters{}, HTTPHeaderHashFilters{}, "", UrlRewriteMap{}, 0)

Plugins.Inputs = []io.Reader{input}
Plugins.Outputs = []io.Writer{output}

go Start(quit)

wg.Add(1)
input.EmitChunkedPOST()

wg.Wait()

close(quit)
}

func BenchmarkHTTPOutput(b *testing.B) {
wg := new(sync.WaitGroup)
quit := make(chan int)
Expand Down
2 changes: 1 addition & 1 deletion settings_header_hash_filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (h *HTTPHeaderHashFilters) Set(value string) error {
panic("need positive numerators and denominators, with the former less than the latter.")
}

if den & (den - 1) != 0 {
if den&(den-1) != 0 {
return errors.New("must have a denominator which is a power of two.")
}

Expand Down
6 changes: 5 additions & 1 deletion test_input.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ func (i *TestInput) EmitGET() {
}

func (i *TestInput) EmitPOST() {
i.data <- []byte("POST /pub/WWW/ HTTP/1.1\nHost: www.w3.org\r\n\r\na=1&b=2\r\n\r\n")
i.data <- []byte("POST /pub/WWW/ HTTP/1.1\nHost: www.w3.org\r\n\r\na=1&b=2")
}

func (i *TestInput) EmitChunkedPOST() {
i.data <- []byte("POST /pub/WWW/ HTTP/1.1\nHost: www.w3.org\nTransfer-Encoding: chunked\r\n\r\n4\r\nWiki\r\n5\r\npedia\r\ne\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n")
}

func (i *TestInput) EmitFile() {
Expand Down

0 comments on commit 6fe7ba8

Please sign in to comment.