Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(rpc): Fix http batch request to handle single item requests #3694

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions tm2/pkg/bft/rpc/lib/client/http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"net"
"net/http"
"reflect"
"strings"

types "github.com/gnolang/gno/tm2/pkg/bft/rpc/lib/types"
Expand Down Expand Up @@ -115,7 +116,8 @@ func sendRequestCommon[T requestType, R responseType](
// Marshal the request
requestBytes, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("unable to JSON-marshal the request, %w", err)
var zero R
return zero, fmt.Errorf("unable to JSON-marshal the request, %w", err)
masonmcbride marked this conversation as resolved.
Show resolved Hide resolved
}

// Craft the request
Expand All @@ -125,7 +127,8 @@ func sendRequestCommon[T requestType, R responseType](
bytes.NewBuffer(requestBytes),
)
if err != nil {
return nil, fmt.Errorf("unable to create request, %w", err)
var zero R
return zero, fmt.Errorf("unable to create request, %w", err)
}

// Set the header content type
Expand All @@ -134,25 +137,41 @@ func sendRequestCommon[T requestType, R responseType](
// Execute the request
httpResponse, err := client.Do(req.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("unable to send request, %w", err)
var zero R
return zero, fmt.Errorf("unable to send request, %w", err)
}
defer httpResponse.Body.Close() //nolint: errcheck

// Parse the response code
if !isOKStatus(httpResponse.StatusCode) {
return nil, fmt.Errorf("invalid status code received, %d", httpResponse.StatusCode)
var zero R
return zero, fmt.Errorf("invalid status code received, %d", httpResponse.StatusCode)
}

// Parse the response body
responseBytes, err := io.ReadAll(httpResponse.Body)
if err != nil {
return nil, fmt.Errorf("unable to read response body, %w", err)
var zero R
return zero, fmt.Errorf("unable to read response body, %w", err)
}

var response R

if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, fmt.Errorf("unable to unmarshal response body, %w", err)
// If unmarshal fails, and if R is a slice, try to unmarshal as a single element.
var zero R
rType := reflect.TypeOf(zero)
if rType.Kind() == reflect.Slice {
elemType := rType.Elem()
singlePtr := reflect.New(elemType).Interface()
if err2 := json.Unmarshal(responseBytes, singlePtr); err2 == nil {
newSlice := reflect.MakeSlice(rType, 0, 1)
newSlice = reflect.Append(newSlice, reflect.ValueOf(singlePtr).Elem())
response = newSlice.Interface().(R)
return response, nil
}
}
masonmcbride marked this conversation as resolved.
Show resolved Hide resolved
return zero, fmt.Errorf("unable to unmarshal response body, %w", err)
}

return response, nil
Expand Down