aboutsummaryrefslogtreecommitdiffstats
path: root/common/docserver
diff options
context:
space:
mode:
Diffstat (limited to 'common/docserver')
-rw-r--r--common/docserver/docserver.go82
-rw-r--r--common/docserver/docserver_test.go38
2 files changed, 120 insertions, 0 deletions
diff --git a/common/docserver/docserver.go b/common/docserver/docserver.go
new file mode 100644
index 000000000..5e076aa7e
--- /dev/null
+++ b/common/docserver/docserver.go
@@ -0,0 +1,82 @@
+package docserver
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+// http://golang.org/pkg/net/http/#RoundTripper
+var (
+ schemes = map[string]func(*DocServer) http.RoundTripper{
+ // Simple File server from local disk file:///etc/passwd :)
+ "file": fileServerOnDocRoot,
+ }
+)
+
+func fileServerOnDocRoot(ds *DocServer) http.RoundTripper {
+ return http.NewFileTransport(http.Dir(ds.DocRoot))
+}
+
+type DocServer struct {
+ *http.Transport
+ DocRoot string
+}
+
+func New(docRoot string) (self *DocServer, err error) {
+ self = &DocServer{
+ Transport: &http.Transport{},
+ DocRoot: docRoot,
+ }
+ err = self.RegisterProtocols(schemes)
+ return
+}
+
+// Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
+
+// A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
+
+func (self *DocServer) Client() *http.Client {
+ return &http.Client{
+ Transport: self,
+ }
+}
+
+func (self *DocServer) RegisterProtocols(schemes map[string]func(*DocServer) http.RoundTripper) (err error) {
+ for scheme, rtf := range schemes {
+ self.RegisterProtocol(scheme, rtf(self))
+ }
+ return
+}
+
+func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
+ // retrieve content
+ resp, err := self.Client().Get(uri)
+ defer func() {
+ if resp != nil {
+ resp.Body.Close()
+ }
+ }()
+ if err != nil {
+ return
+ }
+ content, err = ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return
+ }
+
+ // check hash to authenticate content
+ hashbytes := crypto.Sha3(content)
+ var chash common.Hash
+ copy(chash[:], hashbytes)
+ if chash != hash {
+ content = nil
+ err = fmt.Errorf("content hash mismatch")
+ }
+
+ return
+
+}
diff --git a/common/docserver/docserver_test.go b/common/docserver/docserver_test.go
new file mode 100644
index 000000000..400d7447a
--- /dev/null
+++ b/common/docserver/docserver_test.go
@@ -0,0 +1,38 @@
+package docserver
+
+import (
+ "io/ioutil"
+ "os"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+func TestGetAuthContent(t *testing.T) {
+ text := "test"
+ hash := common.Hash{}
+ copy(hash[:], crypto.Sha3([]byte(text)))
+ ioutil.WriteFile("/tmp/test.content", []byte(text), os.ModePerm)
+
+ ds, err := New("/tmp/")
+ content, err := ds.GetAuthContent("file:///test.content", hash)
+ if err != nil {
+ t.Errorf("no error expected, got %v", err)
+ }
+ if string(content) != text {
+ t.Errorf("incorrect content. expected %v, got %v", text, string(content))
+ }
+
+ hash = common.Hash{}
+ content, err = ds.GetAuthContent("file:///test.content", hash)
+ expected := "content hash mismatch"
+ if err == nil {
+ t.Errorf("expected error, got nothing")
+ } else {
+ if err.Error() != expected {
+ t.Errorf("expected error '%s' got '%v'", expected, err)
+ }
+ }
+
+}