gitlab.com/jokerrs1/Sia@v1.3.2/node/api/api.go (about) 1 package api 2 3 import ( 4 "encoding/json" 5 "net/http" 6 "strings" 7 8 "github.com/NebulousLabs/Sia/build" 9 "github.com/NebulousLabs/Sia/modules" 10 ) 11 12 // Error is a type that is encoded as JSON and returned in an API response in 13 // the event of an error. Only the Message field is required. More fields may 14 // be added to this struct in the future for better error reporting. 15 type Error struct { 16 // Message describes the error in English. Typically it is set to 17 // `err.Error()`. This field is required. 18 Message string `json:"message"` 19 20 // TODO: add a Param field with the (omitempty option in the json tag) 21 // to indicate that the error was caused by an invalid, missing, or 22 // incorrect parameter. This is not trivial as the API does not 23 // currently do parameter validation itself. For example, the 24 // /gateway/connect endpoint relies on the gateway.Connect method to 25 // validate the netaddress. However, this prevents the API from knowing 26 // whether an error returned by gateway.Connect is because of a 27 // connection error or an invalid netaddress parameter. Validating 28 // parameters in the API is not sufficient, as a parameter's value may 29 // be valid or invalid depending on the current state of a module. 30 } 31 32 // Error implements the error interface for the Error type. It returns only the 33 // Message field. 34 func (err Error) Error() string { 35 return err.Message 36 } 37 38 // HttpGET is a utility function for making http get requests to sia with a 39 // whitelisted user-agent. A non-2xx response does not return an error. 40 func HttpGET(url string) (resp *http.Response, err error) { 41 req, err := http.NewRequest("GET", url, nil) 42 if err != nil { 43 return nil, err 44 } 45 req.Header.Set("User-Agent", "Sia-Agent") 46 return http.DefaultClient.Do(req) 47 } 48 49 // HttpGETAuthenticated is a utility function for making authenticated http get 50 // requests to sia with a whitelisted user-agent and the supplied password. A 51 // non-2xx response does not return an error. 52 func HttpGETAuthenticated(url string, password string) (resp *http.Response, err error) { 53 req, err := http.NewRequest("GET", url, nil) 54 if err != nil { 55 return nil, err 56 } 57 req.Header.Set("User-Agent", "Sia-Agent") 58 req.SetBasicAuth("", password) 59 return http.DefaultClient.Do(req) 60 } 61 62 // HttpPOST is a utility function for making post requests to sia with a 63 // whitelisted user-agent. A non-2xx response does not return an error. 64 func HttpPOST(url string, data string) (resp *http.Response, err error) { 65 req, err := http.NewRequest("POST", url, strings.NewReader(data)) 66 if err != nil { 67 return nil, err 68 } 69 req.Header.Set("User-Agent", "Sia-Agent") 70 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 71 return http.DefaultClient.Do(req) 72 } 73 74 // HttpPOSTAuthenticated is a utility function for making authenticated http 75 // post requests to sia with a whitelisted user-agent and the supplied 76 // password. A non-2xx response does not return an error. 77 func HttpPOSTAuthenticated(url string, data string, password string) (resp *http.Response, err error) { 78 req, err := http.NewRequest("POST", url, strings.NewReader(data)) 79 if err != nil { 80 return nil, err 81 } 82 req.Header.Set("User-Agent", "Sia-Agent") 83 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 84 req.SetBasicAuth("", password) 85 return http.DefaultClient.Do(req) 86 } 87 88 // API encapsulates a collection of modules and implements a http.Handler 89 // to access their methods. 90 type API struct { 91 cs modules.ConsensusSet 92 explorer modules.Explorer 93 gateway modules.Gateway 94 host modules.Host 95 miner modules.Miner 96 renter modules.Renter 97 tpool modules.TransactionPool 98 wallet modules.Wallet 99 100 router http.Handler 101 } 102 103 // api.ServeHTTP implements the http.Handler interface. 104 func (api *API) ServeHTTP(w http.ResponseWriter, r *http.Request) { 105 api.router.ServeHTTP(w, r) 106 } 107 108 // New creates a new Sia API from the provided modules. The API will require 109 // authentication using HTTP basic auth for certain endpoints of the supplied 110 // password is not the empty string. Usernames are ignored for authentication. 111 func New(requiredUserAgent string, requiredPassword string, cs modules.ConsensusSet, e modules.Explorer, g modules.Gateway, h modules.Host, m modules.Miner, r modules.Renter, tp modules.TransactionPool, w modules.Wallet) *API { 112 api := &API{ 113 cs: cs, 114 explorer: e, 115 gateway: g, 116 host: h, 117 miner: m, 118 renter: r, 119 tpool: tp, 120 wallet: w, 121 } 122 123 // Register API handlers 124 api.buildHTTPRoutes(requiredUserAgent, requiredPassword) 125 126 return api 127 } 128 129 // UnrecognizedCallHandler handles calls to unknown pages (404). 130 func UnrecognizedCallHandler(w http.ResponseWriter, req *http.Request) { 131 WriteError(w, Error{"404 - Refer to API.md"}, http.StatusNotFound) 132 } 133 134 // WriteError an error to the API caller. 135 func WriteError(w http.ResponseWriter, err Error, code int) { 136 w.Header().Set("Content-Type", "application/json; charset=utf-8") 137 w.WriteHeader(code) 138 encodingErr := json.NewEncoder(w).Encode(err) 139 if _, isJsonErr := encodingErr.(*json.SyntaxError); isJsonErr { 140 // Marshalling should only fail in the event of a developer error. 141 // Specifically, only non-marshallable types should cause an error here. 142 build.Critical("failed to encode API error response:", encodingErr) 143 } 144 } 145 146 // WriteJSON writes the object to the ResponseWriter. If the encoding fails, an 147 // error is written instead. The Content-Type of the response header is set 148 // accordingly. 149 func WriteJSON(w http.ResponseWriter, obj interface{}) { 150 w.Header().Set("Content-Type", "application/json; charset=utf-8") 151 err := json.NewEncoder(w).Encode(obj) 152 if _, isJsonErr := err.(*json.SyntaxError); isJsonErr { 153 // Marshalling should only fail in the event of a developer error. 154 // Specifically, only non-marshallable types should cause an error here. 155 build.Critical("failed to encode API response:", err) 156 } 157 } 158 159 // WriteSuccess writes the HTTP header with status 204 No Content to the 160 // ResponseWriter. WriteSuccess should only be used to indicate that the 161 // requested action succeeded AND there is no data to return. 162 func WriteSuccess(w http.ResponseWriter) { 163 w.WriteHeader(http.StatusNoContent) 164 }