| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 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) | 
					
						
							| 
									
										
										
										
											2015-04-06 08:01:36 +02:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if resp != nil { | 
					
						
							|  |  |  | 			resp.Body.Close() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |