docserver.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package docserver
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "github.com/ethereum/go-ethereum/common"
  7. "github.com/ethereum/go-ethereum/crypto"
  8. )
  9. // http://golang.org/pkg/net/http/#RoundTripper
  10. var (
  11. schemes = map[string]func(*DocServer) http.RoundTripper{
  12. // Simple File server from local disk file:///etc/passwd :)
  13. "file": fileServerOnDocRoot,
  14. }
  15. )
  16. func fileServerOnDocRoot(ds *DocServer) http.RoundTripper {
  17. return http.NewFileTransport(http.Dir(ds.DocRoot))
  18. }
  19. type DocServer struct {
  20. *http.Transport
  21. DocRoot string
  22. }
  23. func New(docRoot string) (self *DocServer, err error) {
  24. self = &DocServer{
  25. Transport: &http.Transport{},
  26. DocRoot: docRoot,
  27. }
  28. err = self.RegisterProtocols(schemes)
  29. return
  30. }
  31. // Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
  32. // A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
  33. func (self *DocServer) Client() *http.Client {
  34. return &http.Client{
  35. Transport: self,
  36. }
  37. }
  38. func (self *DocServer) RegisterProtocols(schemes map[string]func(*DocServer) http.RoundTripper) (err error) {
  39. for scheme, rtf := range schemes {
  40. self.RegisterProtocol(scheme, rtf(self))
  41. }
  42. return
  43. }
  44. func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
  45. // retrieve content
  46. resp, err := self.Client().Get(uri)
  47. defer func() {
  48. if resp != nil {
  49. resp.Body.Close()
  50. }
  51. }()
  52. if err != nil {
  53. return
  54. }
  55. content, err = ioutil.ReadAll(resp.Body)
  56. if err != nil {
  57. return
  58. }
  59. // check hash to authenticate content
  60. hashbytes := crypto.Sha3(content)
  61. var chash common.Hash
  62. copy(chash[:], hashbytes)
  63. if chash != hash {
  64. content = nil
  65. err = fmt.Errorf("content hash mismatch")
  66. }
  67. return
  68. }