From 77c64e97b6d064947776ab0bdd63dae025484c0e Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Thu, 25 Oct 2018 19:40:07 +0200 Subject: [PATCH] Add apiSendTx via POST request --- server/public.go | 48 ++++++++++++++++++++++++++++--------------- server/public_test.go | 35 +++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/server/public.go b/server/public.go index 644aa207..1996240b 100644 --- a/server/public.go +++ b/server/public.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "html/template" + "io/ioutil" "math/big" "net/http" "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) { type jsonError struct { - Error string `json:"error"` + Text string `json:"error"` + HTTPStatus int `json:"-"` } return func(w http.ResponseWriter, r *http.Request) { var data interface{} @@ -200,33 +202,37 @@ func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, e if e := recover(); e != nil { glog.Error(getFunctionName(handler), " recovered from panic: ", e) 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 { - data = jsonError{"Internal server error"} + data = jsonError{"Internal server error", http.StatusInternalServerError} } } w.Header().Set("Content-Type", "application/json; charset=utf-8") - if _, isError := data.(jsonError); isError { - w.WriteHeader(http.StatusInternalServerError) + if e, isError := data.(jsonError); isError { + w.WriteHeader(e.HTTPStatus) } json.NewEncoder(w).Encode(data) }() data, err = handler(r) if err != nil || data == nil { 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 { if err != nil { glog.Error(getFunctionName(handler), " error: ", err) } if s.debug { 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 { - data = jsonError{fmt.Sprintf("Internal server error: %v", err)} + data = jsonError{fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError} } } 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) { var err error var res resultSendTransaction + var hex string s.metrics.ExplorerViews.With(common.Labels{"action": "api-sendtx"}).Inc() - if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 { - hex := r.URL.Path[i+1:] - if len(hex) > 0 { - if len(hex) > 0 { - res.Result, err = s.chain.SendRawTransaction(hex) - return res, err - } + if r.Method == http.MethodPost { + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, api.NewApiError("Missing tx blob", true) } + 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) } diff --git a/server/public_test.go b/server/public_test.go index 53cef7a4..3a1e5b6e 100644 --- a/server/public_test.go +++ b/server/public_test.go @@ -109,7 +109,7 @@ func newGetRequest(u string) *http.Request { return r } -func newPostRequest(u string, formdata ...string) *http.Request { +func newPostFormRequest(u string, formdata ...string) *http.Request { form := url.Values{} for i := 0; i < len(formdata)-1; i += 2 { form.Add(formdata[i], formdata[i+1]) @@ -122,6 +122,15 @@ func newPostRequest(u string, formdata ...string) *http.Request { 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) { tests := []struct { name string @@ -331,7 +340,7 @@ func httpTests(t *testing.T, ts *httptest.Server) { }, { name: "explorerSendTx POST", - r: newPostRequest(ts.URL+"/sendtx", "hex", "12341234"), + r: newPostFormRequest(ts.URL+"/sendtx", "hex", "12341234"), status: http.StatusOK, contentType: "text/html; charset=utf-8", body: []string{ @@ -375,7 +384,7 @@ func httpTests(t *testing.T, ts *httptest.Server) { { name: "apiTx - not found", r: newGetRequest(ts.URL + "/api/tx/1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"), - status: http.StatusInternalServerError, + status: http.StatusBadRequest, contentType: "application/json; charset=utf-8", body: []string{ `{"error":"Tx not found, Not found"}`, @@ -401,13 +410,31 @@ func httpTests(t *testing.T, ts *httptest.Server) { }, { 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, contentType: "application/json; charset=utf-8", body: []string{ `{"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", r: newGetRequest(ts.URL + "/api/estimatefee/123?conservative=false"),