| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | package httpclient | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | type HTTPClient struct { | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	*http.Transport | 
					
						
							|  |  |  | 	DocRoot string | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	schemes []string | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | func New(docRoot string) (self *HTTPClient) { | 
					
						
							|  |  |  | 	self = &HTTPClient{ | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 		Transport: &http.Transport{}, | 
					
						
							|  |  |  | 		DocRoot:   docRoot, | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 		schemes:   []string{"file"}, | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot))) | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | func (self *HTTPClient) Client() *http.Client { | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	return &http.Client{ | 
					
						
							|  |  |  | 		Transport: self, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | func (self *HTTPClient) RegisterScheme(scheme string, rt http.RoundTripper) { | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	self.schemes = append(self.schemes, scheme) | 
					
						
							|  |  |  | 	self.RegisterProtocol(scheme, rt) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | func (self *HTTPClient) HasScheme(scheme string) bool { | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	for _, s := range self.schemes { | 
					
						
							|  |  |  | 		if s == scheme { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	return false | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | func (self *HTTPClient) GetAuthContent(uri string, hash common.Hash) ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	// retrieve content | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 	content, err := self.Get(uri, "") | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// check hash to authenticate content | 
					
						
							| 
									
										
										
										
											2016-02-21 18:40:27 +00:00
										 |  |  | 	chash := crypto.Keccak256Hash(content) | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	if chash != hash { | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 		return nil, fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:]) | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 	return content, nil | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get(uri, path) downloads the document at uri, if path is non-empty it | 
					
						
							|  |  |  | // is interpreted as a filepath to which the contents are saved | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | func (self *HTTPClient) Get(uri, path string) ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	// retrieve content | 
					
						
							|  |  |  | 	resp, err := self.Client().Get(uri) | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-06 08:01:36 +02:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if resp != nil { | 
					
						
							|  |  |  | 			resp.Body.Close() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-09-22 10:34:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 	var content []byte | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	content, err = ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-22 10:34:58 +02:00
										 |  |  | 	if resp.StatusCode/100 != 2 { | 
					
						
							|  |  |  | 		return content, fmt.Errorf("HTTP error: %s", resp.Status) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	if path != "" { | 
					
						
							|  |  |  | 		var abspath string | 
					
						
							|  |  |  | 		abspath, err = filepath.Abs(path) | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = ioutil.WriteFile(abspath, content, 0600) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-26 22:24:09 +01:00
										 |  |  | 	return content, nil | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |