Skip to content

Commit

Permalink
Implement curl exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
instabledesign committed Feb 5, 2021
1 parent 1cebe65 commit 56f976e
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 0 deletions.
63 changes: 63 additions & 0 deletions exporter/curl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package exporter

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

func CurlFmtPrinter(cmd *Cmd, err error) {
if err == nil {
fmt.Println(cmd)
return
}
fmt.Println("cannot print curl command", err)
}

type Cmd []string

func (c *Cmd) append(newSlice ...string) {
*c = append(*c, newSlice...)
}

func (c *Cmd) String() string {
return strings.Join(*c, " ")
}

type nopCloser struct {
io.Reader
}

func (nopCloser) Close() error { return nil }

func escape(str string) string {
return `'` + strings.Replace(str, `'`, `'\''`, -1) + `'`
}

func GetCurlCommand(req *http.Request) (*Cmd, error) {
cmd := &Cmd{
"curl",
"-X", escape(req.Method),
escape(req.URL.String()),
}

if req.Body != nil {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
req.Body = nopCloser{bytes.NewBuffer(body)}
if len(string(body)) > 0 {
cmd.append("-d", escape(string(body)))
}
}

for h := range req.Header {
cmd.append("-H", escape(h+": "+strings.Join(req.Header[h], " ")))
}

return cmd, nil
}
17 changes: 17 additions & 0 deletions middleware/curl_exporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package middleware

import (
"net/http"

"github.com/gol4ng/httpware/v4"
"github.com/gol4ng/httpware/v4/exporter"
)

func CurlExporter(printer func(*exporter.Cmd, error)) httpware.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
printer(exporter.GetCurlCommand(request))
next.ServeHTTP(writer, request)
})
}
}
38 changes: 38 additions & 0 deletions middleware/curl_exporter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package middleware_test

import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"

"github.com/gol4ng/httpware/v4/exporter"
"github.com/gol4ng/httpware/v4/middleware"
"github.com/stretchr/testify/assert"
)

func TestCurlExporter(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://fake-addr", ioutil.NopCloser(strings.NewReader(url.Values{
"mykey": {"myvalue"},
}.Encode())))
responseWriter := &httptest.ResponseRecorder{}

handlerCalled := false
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, req, r)
handlerCalled = true
})

called := false
mockExporter := func(cmd *exporter.Cmd, err error) {
called = true
assert.Equal(t, "curl -X 'GET' 'http://fake-addr' -d 'mykey=myvalue'", cmd.String())
assert.Nil(t, err)
}

middleware.CurlExporter(mockExporter)(handler).ServeHTTP(responseWriter, req)
assert.True(t, called)
assert.True(t, handlerCalled)
}
17 changes: 17 additions & 0 deletions tripperware/curl_exporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package tripperware

import (
"net/http"

"github.com/gol4ng/httpware/v4"
"github.com/gol4ng/httpware/v4/exporter"
)

func CurlExporter(export func(*exporter.Cmd, error)) httpware.Tripperware {
return func(next http.RoundTripper) http.RoundTripper {
return httpware.RoundTripFunc(func(request *http.Request) (*http.Response, error) {
export(exporter.GetCurlCommand(request))
return next.RoundTrip(request)
})
}
}
43 changes: 43 additions & 0 deletions tripperware/curl_exporter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package tripperware_test

import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

"github.com/gol4ng/httpware/v4/exporter"
"github.com/gol4ng/httpware/v4/mocks"
"github.com/gol4ng/httpware/v4/tripperware"
)

func TestCurlExporter(t *testing.T) {
roundTripperMock := &mocks.RoundTripper{}
req := httptest.NewRequest(http.MethodGet, "http://fake-addr", ioutil.NopCloser(strings.NewReader(url.Values{
"mykey": {"myvalue"},
}.Encode())))

resp := &http.Response{
Status: "OK",
StatusCode: http.StatusOK,
ContentLength: 30,
}

roundTripperMock.On("RoundTrip", mock.AnythingOfType("*http.Request")).Return(resp, nil)

called := false
mockExporter := func(cmd *exporter.Cmd, err error) {
called = true
assert.Equal(t, "curl -X 'GET' 'http://fake-addr' -d 'mykey=myvalue'", cmd.String())
assert.Nil(t, err)
}
resp2, err := tripperware.CurlExporter(mockExporter)(roundTripperMock).RoundTrip(req)
assert.Nil(t, err)
assert.Equal(t, resp, resp2)
assert.True(t, called)
}

0 comments on commit 56f976e

Please sign in to comment.