docserver.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package docserver
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "path/filepath"
  7. "github.com/ethereum/go-ethereum/common"
  8. "github.com/ethereum/go-ethereum/crypto"
  9. )
  10. type DocServer struct {
  11. *http.Transport
  12. DocRoot string
  13. schemes []string
  14. }
  15. func New(docRoot string) (self *DocServer) {
  16. self = &DocServer{
  17. Transport: &http.Transport{},
  18. DocRoot: docRoot,
  19. schemes: []string{"file"},
  20. }
  21. self.DocRoot = "/tmp/"
  22. self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
  23. return
  24. }
  25. // Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
  26. // A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
  27. func (self *DocServer) Client() *http.Client {
  28. return &http.Client{
  29. Transport: self,
  30. }
  31. }
  32. func (self *DocServer) RegisterScheme(scheme string, rt http.RoundTripper) {
  33. self.schemes = append(self.schemes, scheme)
  34. self.RegisterProtocol(scheme, rt)
  35. }
  36. func (self *DocServer) HasScheme(scheme string) bool {
  37. for _, s := range self.schemes {
  38. if s == scheme {
  39. return true
  40. }
  41. }
  42. return false
  43. }
  44. func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
  45. // retrieve content
  46. content, err = self.Get(uri, "")
  47. if err != nil {
  48. return
  49. }
  50. // check hash to authenticate content
  51. chash := crypto.Sha3Hash(content)
  52. if chash != hash {
  53. content = nil
  54. err = fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
  55. }
  56. return
  57. }
  58. // Get(uri, path) downloads the document at uri, if path is non-empty it
  59. // is interpreted as a filepath to which the contents are saved
  60. func (self *DocServer) Get(uri, path string) (content []byte, err error) {
  61. // retrieve content
  62. resp, err := self.Client().Get(uri)
  63. defer func() {
  64. if resp != nil {
  65. resp.Body.Close()
  66. }
  67. }()
  68. if err != nil {
  69. return
  70. }
  71. content, err = ioutil.ReadAll(resp.Body)
  72. if err != nil {
  73. return
  74. }
  75. if path != "" {
  76. var abspath string
  77. abspath, err = filepath.Abs(path)
  78. ioutil.WriteFile(abspath, content, 0700)
  79. }
  80. return
  81. }