Commit f68594a4 authored by Luke Champine's avatar Luke Champine

use httprouter package

this necessitated changing the explorer API a bit, since it would
be ambiguous according to httprouter's routing rules. Next, the
API functions will be migrated to their httprouter equivalents,
which should eliminate a lot of "wrong method" handling code.
parent a4544848
......@@ -19,6 +19,7 @@ dependencies:
go get -u github.com/inconshreveable/muxado
go get -u github.com/kardianos/osext
go get -u github.com/klauspost/reedsolomon
go get -u github.com/julienschmidt/httprouter
# Frontend Dependencies
go get -u github.com/bgentry/speakeasy
go get -u github.com/spf13/cobra
......
......@@ -5,6 +5,8 @@ import (
"fmt"
"net/http"
"strings"
"github.com/julienschmidt/httprouter"
)
// HttpGET is a utility function for making http get requests to sia with a whitelisted user-agent
......@@ -42,99 +44,99 @@ func requireUserAgent(h http.Handler, ua string) http.Handler {
// initAPI determines which functions handle each API call.
func (srv *Server) initAPI() {
mux := http.NewServeMux()
// 404 Calls
mux.HandleFunc("/", srv.unrecognizedCallHandler)
mux := httprouter.New()
mux.NotFound = http.HandlerFunc(srv.unrecognizedCallHandler) // custom 404
// Daemon API Calls - Unfinished
mux.HandleFunc("/daemon/constants", srv.daemonConstantsHandler)
mux.HandleFunc("/daemon/version", srv.daemonVersionHandler)
mux.HandleFunc("/daemon/stop", srv.daemonStopHandler)
mux.HandleFunc("/daemon/updates/apply", srv.daemonUpdatesApplyHandler)
mux.HandleFunc("/daemon/updates/check", srv.daemonUpdatesCheckHandler)
mux.HandlerFunc("GET", "/daemon/constants", srv.daemonConstantsHandler)
mux.HandlerFunc("GET", "/daemon/version", srv.daemonVersionHandler)
mux.HandlerFunc("GET", "/daemon/stop", srv.daemonStopHandler)
mux.HandlerFunc("GET", "/daemon/updates/apply", srv.daemonUpdatesApplyHandler)
mux.HandlerFunc("GET", "/daemon/updates/check", srv.daemonUpdatesCheckHandler)
// Consensus API Calls
if srv.cs != nil {
mux.HandleFunc("/consensus", srv.consensusHandler) // GET
mux.HandleFunc("/consensus/block", srv.consensusBlockHandler) // GET
mux.HandlerFunc("GET", "/consensus", srv.consensusHandler)
mux.HandlerFunc("GET", "/consensus/block", srv.consensusBlockHandler)
}
// Explorer API Calls
if srv.explorer != nil {
mux.HandleFunc("/explorer", srv.explorerHandler) // GET
mux.HandleFunc("/explorer/", srv.explorerHandler) // $(hash) GET
mux.HandleFunc("/explorer/block", srv.explorerBlockHandler) // GET
mux.HandlerFunc("GET", "/explorer", srv.explorerHandler)
mux.HandlerFunc("GET", "/explorer/hash/:hash", srv.explorerHashHandler)
mux.HandlerFunc("GET", "/explorer/block/:height", srv.explorerBlockHandler)
}
// Gateway API Calls - Unfinished
if srv.gateway != nil {
mux.HandleFunc("/gateway/status", srv.gatewayStatusHandler)
mux.HandleFunc("/gateway/peers/add", srv.gatewayPeersAddHandler)
mux.HandleFunc("/gateway/peers/remove", srv.gatewayPeersRemoveHandler)
mux.HandlerFunc("GET", "/gateway/status", srv.gatewayStatusHandler)
mux.HandlerFunc("GET", "/gateway/peers/add", srv.gatewayPeersAddHandler)
mux.HandlerFunc("GET", "/gateway/peers/remove", srv.gatewayPeersRemoveHandler)
}
// Host API Calls
if srv.host != nil {
mux.HandleFunc("/host", srv.hostHandler) // GET, POST
mux.HandleFunc("/host/announce", srv.hostAnnounceHandler) // POST
mux.HandlerFunc("GET", "/host", srv.hostHandler)
mux.HandlerFunc("POST", "/host", srv.hostHandler)
mux.HandlerFunc("POST", "/host/announce", srv.hostAnnounceHandler)
}
// HostDB API Calls - DEPRECATED
if srv.renter != nil {
mux.HandleFunc("/hostdb/hosts/active", srv.renterHostsActiveHandler)
mux.HandleFunc("/hostdb/hosts/all", srv.renterHostsAllHandler)
mux.HandlerFunc("GET", "/hostdb/hosts/active", srv.renterHostsActiveHandler)
mux.HandlerFunc("GET", "/hostdb/hosts/all", srv.renterHostsAllHandler)
}
// Miner API Calls
if srv.miner != nil {
mux.HandleFunc("/miner", srv.minerHandler) // GET
mux.HandleFunc("/miner/header", srv.minerHeaderHandler) // GET, POST
mux.HandleFunc("/miner/start", srv.minerStartHandler) // POST
mux.HandleFunc("/miner/stop", srv.minerStopHandler) // POST
mux.HandleFunc("/miner/headerforwork", srv.minerHeaderforworkHandler) // COMPATv0.4.8
mux.HandleFunc("/miner/submitheader", srv.minerSubmitheaderHandler) // COMPATv0.4.8
mux.HandlerFunc("GET", "/miner", srv.minerHandler)
mux.HandlerFunc("GET", "/miner/header", srv.minerHeaderHandler)
mux.HandlerFunc("POST", "/miner/header", srv.minerHeaderHandler)
mux.HandlerFunc("POST", "/miner/start", srv.minerStartHandler)
mux.HandlerFunc("POST", "/miner/stop", srv.minerStopHandler)
mux.HandlerFunc("GET", "/miner/headerforwork", srv.minerHeaderforworkHandler) // COMPATv0.4.8
mux.HandlerFunc("GET", "/miner/submitheader", srv.minerSubmitheaderHandler) // COMPATv0.4.8
}
// Renter API Calls - Unfinished
if srv.renter != nil {
mux.HandleFunc("/renter/downloadqueue", srv.renterDownloadqueueHandler)
mux.HandleFunc("/renter/files/delete", srv.renterFilesDeleteHandler)
mux.HandleFunc("/renter/files/download", srv.renterFilesDownloadHandler)
mux.HandleFunc("/renter/files/list", srv.renterFilesListHandler)
mux.HandleFunc("/renter/files/load", srv.renterFilesLoadHandler)
mux.HandleFunc("/renter/files/loadascii", srv.renterFilesLoadAsciiHandler)
mux.HandleFunc("/renter/files/rename", srv.renterFilesRenameHandler)
mux.HandleFunc("/renter/files/share", srv.renterFilesShareHandler)
mux.HandleFunc("/renter/files/shareascii", srv.renterFilesShareAsciiHandler)
mux.HandleFunc("/renter/files/upload", srv.renterFilesUploadHandler)
mux.HandleFunc("/renter/status", srv.renterStatusHandler)
mux.HandlerFunc("GET", "/renter/downloadqueue", srv.renterDownloadqueueHandler)
mux.HandlerFunc("GET", "/renter/files/delete", srv.renterFilesDeleteHandler)
mux.HandlerFunc("GET", "/renter/files/download", srv.renterFilesDownloadHandler)
mux.HandlerFunc("GET", "/renter/files/list", srv.renterFilesListHandler)
mux.HandlerFunc("GET", "/renter/files/load", srv.renterFilesLoadHandler)
mux.HandlerFunc("GET", "/renter/files/loadascii", srv.renterFilesLoadAsciiHandler)
mux.HandlerFunc("GET", "/renter/files/rename", srv.renterFilesRenameHandler)
mux.HandlerFunc("GET", "/renter/files/share", srv.renterFilesShareHandler)
mux.HandlerFunc("GET", "/renter/files/shareascii", srv.renterFilesShareAsciiHandler)
mux.HandlerFunc("GET", "/renter/files/upload", srv.renterFilesUploadHandler)
mux.HandlerFunc("GET", "/renter/status", srv.renterStatusHandler)
}
// TransactionPool API Calls - Unfinished
if srv.tpool != nil {
mux.HandleFunc("/transactionpool/transactions", srv.transactionpoolTransactionsHandler)
mux.HandlerFunc("GET", "/transactionpool/transactions", srv.transactionpoolTransactionsHandler)
}
// Wallet API Calls
if srv.wallet != nil {
mux.HandleFunc("/wallet", srv.walletHandler) // GET
mux.HandleFunc("/wallet/address", srv.walletAddressHandler) // GET
mux.HandleFunc("/wallet/addresses", srv.walletAddressesHandler) // GET
mux.HandleFunc("/wallet/backup", srv.walletBackupHandler) // GET
mux.HandleFunc("/wallet/encrypt", srv.walletEncryptHandler) // POST - COMPATv0.4.0
mux.HandleFunc("/wallet/init", srv.walletInitHandler) // POST
mux.HandleFunc("/wallet/load/033x", srv.walletLoad033xHandler) // POST
mux.HandleFunc("/wallet/load/seed", srv.walletLoadSeedHandler) // POST
mux.HandleFunc("/wallet/load/siag", srv.walletLoadSiagHandler) // POST
mux.HandleFunc("/wallet/lock", srv.walletLockHandler) // POST
mux.HandleFunc("/wallet/seeds", srv.walletSeedsHandler) // GET
mux.HandleFunc("/wallet/siacoins", srv.walletSiacoinsHandler) // POST
mux.HandleFunc("/wallet/siafunds", srv.walletSiafundsHandler) // POST
mux.HandleFunc("/wallet/transaction/", srv.walletTransactionHandler) // $(id) GET
mux.HandleFunc("/wallet/transactions", srv.walletTransactionsHandler) // GET
mux.HandleFunc("/wallet/transactions/", srv.walletTransactionsHandler) // $(addr) GET
mux.HandleFunc("/wallet/unlock", srv.walletUnlockHandler) // POST
mux.HandlerFunc("GET", "/wallet", srv.walletHandler)
mux.HandlerFunc("GET", "/wallet/address", srv.walletAddressHandler)
mux.HandlerFunc("GET", "/wallet/addresses", srv.walletAddressesHandler)
mux.HandlerFunc("GET", "/wallet/backup", srv.walletBackupHandler)
mux.HandlerFunc("POST", "/wallet/encrypt", srv.walletEncryptHandler) // COMPATv0.4.0
mux.HandlerFunc("POST", "/wallet/init", srv.walletInitHandler)
mux.HandlerFunc("POST", "/wallet/load/033x", srv.walletLoad033xHandler)
mux.HandlerFunc("POST", "/wallet/load/seed", srv.walletLoadSeedHandler)
mux.HandlerFunc("POST", "/wallet/load/siag", srv.walletLoadSiagHandler)
mux.HandlerFunc("POST", "/wallet/lock", srv.walletLockHandler)
mux.HandlerFunc("GET", "/wallet/seeds", srv.walletSeedsHandler)
mux.HandlerFunc("POST", "/wallet/siacoins", srv.walletSiacoinsHandler)
mux.HandlerFunc("POST", "/wallet/siafunds", srv.walletSiafundsHandler)
mux.HandlerFunc("GET", "/wallet/transaction/:id", srv.walletTransactionHandler)
mux.HandlerFunc("GET", "/wallet/transactions", srv.walletTransactionsHandler)
mux.HandlerFunc("GET", "/wallet/transactions/:addr", srv.walletTransactionsHandler)
mux.HandlerFunc("POST", "/wallet/unlock", srv.walletUnlockHandler)
}
// Apply UserAgent middleware and create HTTP server
......
......@@ -199,7 +199,7 @@ func (srv *Server) buildExplorerBlock(height types.BlockHeight, block types.Bloc
func (srv *Server) explorerBlockHandlerGET(w http.ResponseWriter, req *http.Request) {
// Parse the height that's being requested.
var height types.BlockHeight
_, err := fmt.Sscan(req.FormValue("height"), &height)
_, err := fmt.Sscan(strings.TrimPrefix(req.URL.Path, "/explorer/block/"), &height)
if err != nil {
writeError(w, err.Error(), http.StatusBadRequest)
return
......@@ -264,12 +264,12 @@ func (srv *Server) explorerHandlerGET(w http.ResponseWriter, req *http.Request)
})
}
// explorerHandlerGEThash handles GET requests to /explorer/$(hash).
func (srv *Server) explorerHandlerGEThash(w http.ResponseWriter, req *http.Request) {
// explorerHashHandler handles GET requests to /explorer/hash/:hash.
func (srv *Server) explorerHashHandler(w http.ResponseWriter, req *http.Request) {
// The hash is scanned as an address, because an address can be typecast to
// all other necessary types, and will correclty decode hashes whether or
// all other necessary types, and will correctly decode hashes whether or
// not they have a checksum.
encodedHash := strings.TrimPrefix(req.URL.Path, "/explorer/")
encodedHash := strings.TrimPrefix(req.URL.Path, "/explorer/hash/")
hash, err := scanAddress(encodedHash)
if err != nil {
writeError(w, err.Error(), http.StatusBadRequest)
......@@ -365,8 +365,6 @@ func (srv *Server) explorerHandlerGEThash(w http.ResponseWriter, req *http.Reque
func (srv *Server) explorerHandler(w http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/explorer" && (req.Method == "" || req.Method == "GET") {
srv.explorerHandlerGET(w, req)
} else if strings.HasPrefix(req.URL.Path, "/explorer/") && (req.Method == "" || req.Method == "GET") {
srv.explorerHandlerGEThash(w, req)
} else {
writeError(w, "unrecognized call to /explorer", http.StatusBadRequest)
}
......
......@@ -42,7 +42,7 @@ func TestIntegrationExplorerBlockGET(t *testing.T) {
defer st.server.Close()
var ebg ExplorerBlockGET
err = st.getAPI("/explorer/block?height=0", &ebg)
err = st.getAPI("/explorer/block/0", &ebg)
if err != nil {
t.Fatal(err)
}
......@@ -54,8 +54,8 @@ func TestIntegrationExplorerBlockGET(t *testing.T) {
}
}
// TestIntegrationExplorerGEThash probes the GET call to /explorer/$(hash).
func TestIntegrationExplorerGEThash(t *testing.T) {
// TestIntegrationExplorerHashGet probes the GET call to /explorer/hash/:hash.
func TestIntegrationExplorerHashGet(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
......@@ -67,7 +67,7 @@ func TestIntegrationExplorerGEThash(t *testing.T) {
var ehg ExplorerHashGET
gb := types.GenesisBlock
err = st.getAPI("/explorer/"+gb.ID().String(), &ehg)
err = st.getAPI("/explorer/hash/"+gb.ID().String(), &ehg)
if err != nil {
t.Fatal(err)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment