Skip to content
This repository was archived by the owner on Oct 5, 2023. It is now read-only.

adds authenticated transport and non-standard api path connections #15

Merged
merged 9 commits into from
May 2, 2019
30 changes: 27 additions & 3 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"net/http"
gohttp "net/http"
"os"
"path"
Expand Down Expand Up @@ -32,9 +33,9 @@ var ErrApiNotFound = errors.New("ipfs api address could not be found")
// For interface docs see
// https://godoc.org/github.com/ipfs/interface-go-ipfs-core#CoreAPI
type HttpApi struct {
url string
httpcli gohttp.Client

url string
httpcli gohttp.Client
Headers http.Header
applyGlobal func(*RequestBuilder)
}

Expand Down Expand Up @@ -111,6 +112,7 @@ func NewApiWithClient(a ma.Multiaddr, c *gohttp.Client) (*HttpApi, error) {
api := &HttpApi{
url: url,
httpcli: *c,
Headers: make(map[string][]string),
applyGlobal: func(*RequestBuilder) {},
}

Expand All @@ -122,6 +124,21 @@ func NewApiWithClient(a ma.Multiaddr, c *gohttp.Client) (*HttpApi, error) {
return api, nil
}

func NewURLApiWithClient(url string, c *gohttp.Client) (*HttpApi, error) {
api := &HttpApi{
url: url,
httpcli: *c,
Headers: make(map[string][]string),
applyGlobal: func(*RequestBuilder) {},
}

// We don't support redirects.
api.httpcli.CheckRedirect = func(_ *gohttp.Request, _ []*gohttp.Request) error {
return fmt.Errorf("unexpected redirect")
}
return api, nil
}

func (api *HttpApi) WithOptions(opts ...caopts.ApiOption) (iface.CoreAPI, error) {
options, err := caopts.ApiOptions(opts...)
if err != nil {
Expand All @@ -139,10 +156,17 @@ func (api *HttpApi) WithOptions(opts ...caopts.ApiOption) (iface.CoreAPI, error)
}

func (api *HttpApi) Request(command string, args ...string) *RequestBuilder {
headers := make(map[string]string)
if api.Headers != nil {
for k := range api.Headers {
headers[k] = api.Headers.Get(k)
}
}
return &RequestBuilder{
command: command,
args: args,
shell: api,
headers: headers,
}
}

Expand Down
54 changes: 53 additions & 1 deletion api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ package httpapi
import (
"context"
"io/ioutil"
"net/http"
gohttp "net/http"
"os"
"strconv"
"sync"
"testing"
"time"

"github.com/ipfs/interface-go-ipfs-core"
"github.com/ipfs/interface-go-ipfs-core/path"

"github.com/ipfs/interface-go-ipfs-core/tests"
local "github.com/ipfs/iptb-plugins/local"
"github.com/ipfs/iptb/testbed"
"github.com/ipfs/iptb/testbed/interfaces"
testbedi "github.com/ipfs/iptb/testbed/interfaces"
ma "github.com/multiformats/go-multiaddr"
)

Expand Down Expand Up @@ -208,3 +211,52 @@ func TestHttpApi(t *testing.T) {

tests.TestApi(newNodeProvider(ctx))(t)
}

func Test_NewURLApiWithClient(t *testing.T) {
t.Skip()
var (
url = "127.0.0.1:65501"
headerToTest = "Test-Header"
expectedHeaderValue = "thisisaheadertest"
)
server, err := testHTTPServer(url, headerToTest, expectedHeaderValue)
if err != nil {
t.Fatal(err)
}
defer server.Close()
go func() {
server.ListenAndServe()
}()
time.Sleep(time.Second * 2)
api, err := NewURLApiWithClient(url, &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DisableKeepAlives: true,
},
})
if err != nil {
t.Fatal(err)
}
api.Headers.Set(headerToTest, expectedHeaderValue)
if _, err := api.Pin().Ls(context.Background()); err != nil {
t.Fatal(err)
}
}

/// testHTTPServer spins up a test go http server
// used to check headers
func testHTTPServer(url, headerToTest, expectedHeaderValue string) (*http.Server, error) {
r := http.NewServeMux()
r.HandleFunc("/api/v0/pin/ls", func(w http.ResponseWriter, r *http.Request) {
val := r.Header.Get(headerToTest)
if val == expectedHeaderValue {
w.WriteHeader(400)
return
}
w.WriteHeader(200)
})
return &http.Server{
Handler: r,
Addr: url,
}, nil
}
21 changes: 21 additions & 0 deletions transport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package httpapi

import "net/http"

type transport struct {
header, value string
httptr http.RoundTripper
}

func newAuthenticatedTransport(tr http.RoundTripper, header, value string) *transport {
return &transport{
header: header,
value: value,
httptr: tr,
}
}

func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header.Set(t.header, t.value)
return t.httptr.RoundTrip(req)
}