Add apiSendTx via POST request

This commit is contained in:
Martin Boehm 2018-10-25 19:40:07 +02:00
parent e9f5dfdc54
commit 77c64e97b6
2 changed files with 63 additions and 20 deletions

View File

@ -9,6 +9,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template" "html/template"
"io/ioutil"
"math/big" "math/big"
"net/http" "net/http"
"reflect" "reflect"
@ -191,7 +192,8 @@ func getFunctionName(i interface{}) string {
func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, error)) func(w http.ResponseWriter, r *http.Request) { func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, error)) func(w http.ResponseWriter, r *http.Request) {
type jsonError struct { type jsonError struct {
Error string `json:"error"` Text string `json:"error"`
HTTPStatus int `json:"-"`
} }
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var data interface{} var data interface{}
@ -200,33 +202,37 @@ func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, e
if e := recover(); e != nil { if e := recover(); e != nil {
glog.Error(getFunctionName(handler), " recovered from panic: ", e) glog.Error(getFunctionName(handler), " recovered from panic: ", e)
if s.debug { if s.debug {
data = jsonError{fmt.Sprint("Internal server error: recovered from panic ", e)} data = jsonError{fmt.Sprint("Internal server error: recovered from panic ", e), http.StatusInternalServerError}
} else { } else {
data = jsonError{"Internal server error"} data = jsonError{"Internal server error", http.StatusInternalServerError}
} }
} }
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
if _, isError := data.(jsonError); isError { if e, isError := data.(jsonError); isError {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(e.HTTPStatus)
} }
json.NewEncoder(w).Encode(data) json.NewEncoder(w).Encode(data)
}() }()
data, err = handler(r) data, err = handler(r)
if err != nil || data == nil { if err != nil || data == nil {
if apiErr, ok := err.(*api.ApiError); ok { if apiErr, ok := err.(*api.ApiError); ok {
data = jsonError{apiErr.Error()} if apiErr.Public {
data = jsonError{apiErr.Error(), http.StatusBadRequest}
} else {
data = jsonError{apiErr.Error(), http.StatusInternalServerError}
}
} else { } else {
if err != nil { if err != nil {
glog.Error(getFunctionName(handler), " error: ", err) glog.Error(getFunctionName(handler), " error: ", err)
} }
if s.debug { if s.debug {
if data != nil { if data != nil {
data = jsonError{fmt.Sprintf("Internal server error: %v, data %+v", err, data)} data = jsonError{fmt.Sprintf("Internal server error: %v, data %+v", err, data), http.StatusInternalServerError}
} else { } else {
data = jsonError{fmt.Sprintf("Internal server error: %v", err)} data = jsonError{fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError}
} }
} else { } else {
data = jsonError{"Internal server error"} data = jsonError{"Internal server error", http.StatusInternalServerError}
} }
} }
} }
@ -700,15 +706,25 @@ type resultSendTransaction struct {
func (s *PublicServer) apiSendTx(r *http.Request) (interface{}, error) { func (s *PublicServer) apiSendTx(r *http.Request) (interface{}, error) {
var err error var err error
var res resultSendTransaction var res resultSendTransaction
var hex string
s.metrics.ExplorerViews.With(common.Labels{"action": "api-sendtx"}).Inc() s.metrics.ExplorerViews.With(common.Labels{"action": "api-sendtx"}).Inc()
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 { if r.Method == http.MethodPost {
hex := r.URL.Path[i+1:] data, err := ioutil.ReadAll(r.Body)
if len(hex) > 0 { if err != nil {
if len(hex) > 0 { return nil, api.NewApiError("Missing tx blob", true)
res.Result, err = s.chain.SendRawTransaction(hex)
return res, err
}
} }
hex = string(data)
} else {
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
hex = r.URL.Path[i+1:]
}
}
if len(hex) > 0 {
res.Result, err = s.chain.SendRawTransaction(hex)
if err != nil {
return nil, api.NewApiError(err.Error(), true)
}
return res, nil
} }
return nil, api.NewApiError("Missing tx blob", true) return nil, api.NewApiError("Missing tx blob", true)
} }

View File

@ -109,7 +109,7 @@ func newGetRequest(u string) *http.Request {
return r return r
} }
func newPostRequest(u string, formdata ...string) *http.Request { func newPostFormRequest(u string, formdata ...string) *http.Request {
form := url.Values{} form := url.Values{}
for i := 0; i < len(formdata)-1; i += 2 { for i := 0; i < len(formdata)-1; i += 2 {
form.Add(formdata[i], formdata[i+1]) form.Add(formdata[i], formdata[i+1])
@ -122,6 +122,15 @@ func newPostRequest(u string, formdata ...string) *http.Request {
return r return r
} }
func newPostRequest(u string, body string) *http.Request {
r, err := http.NewRequest("POST", u, strings.NewReader(body))
if err != nil {
glog.Fatal(err)
}
r.Header.Add("Content-Type", "application/octet-stream")
return r
}
func httpTests(t *testing.T, ts *httptest.Server) { func httpTests(t *testing.T, ts *httptest.Server) {
tests := []struct { tests := []struct {
name string name string
@ -331,7 +340,7 @@ func httpTests(t *testing.T, ts *httptest.Server) {
}, },
{ {
name: "explorerSendTx POST", name: "explorerSendTx POST",
r: newPostRequest(ts.URL+"/sendtx", "hex", "12341234"), r: newPostFormRequest(ts.URL+"/sendtx", "hex", "12341234"),
status: http.StatusOK, status: http.StatusOK,
contentType: "text/html; charset=utf-8", contentType: "text/html; charset=utf-8",
body: []string{ body: []string{
@ -375,7 +384,7 @@ func httpTests(t *testing.T, ts *httptest.Server) {
{ {
name: "apiTx - not found", name: "apiTx - not found",
r: newGetRequest(ts.URL + "/api/tx/1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"), r: newGetRequest(ts.URL + "/api/tx/1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"),
status: http.StatusInternalServerError, status: http.StatusBadRequest,
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
body: []string{ body: []string{
`{"error":"Tx not found, Not found"}`, `{"error":"Tx not found, Not found"}`,
@ -401,13 +410,31 @@ func httpTests(t *testing.T, ts *httptest.Server) {
}, },
{ {
name: "apiSendTx", name: "apiSendTx",
r: newGetRequest(ts.URL + "/api/sendtx/123456"), r: newGetRequest(ts.URL + "/api/sendtx/1234567890"),
status: http.StatusBadRequest,
contentType: "application/json; charset=utf-8",
body: []string{
`{"error":"Invalid data"}`,
},
},
{
name: "apiSendTx POST",
r: newPostRequest(ts.URL+"/api/sendtx/", "123456"),
status: http.StatusOK, status: http.StatusOK,
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
body: []string{ body: []string{
`{"result":"9876"}`, `{"result":"9876"}`,
}, },
}, },
{
name: "apiSendTx POST empty",
r: newPostRequest(ts.URL+"/api/sendtx", ""),
status: http.StatusBadRequest,
contentType: "application/json; charset=utf-8",
body: []string{
`{"error":"Missing tx blob"}`,
},
},
{ {
name: "apiEstimateFee", name: "apiEstimateFee",
r: newGetRequest(ts.URL + "/api/estimatefee/123?conservative=false"), r: newGetRequest(ts.URL + "/api/estimatefee/123?conservative=false"),