diff --git a/http.go b/http.go index cecbbb8..f0d4615 100644 --- a/http.go +++ b/http.go @@ -21,7 +21,6 @@ import ( "github.com/unistack-org/micro/v3/errors" "github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/router" - rutil "github.com/unistack-org/micro/v3/util/reflect" ) var ( @@ -102,21 +101,9 @@ func newRequest(addr string, req client.Request, ct string, cf codec.Codec, msg return nil, errors.BadRequest("go.micro.client", err.Error()) } - var b []byte - - if nmsg != nil { - if ct == "application/x-www-form-urlencoded" { - data, err := rutil.StructURLValues(nmsg, "", tags) - if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) - } - b = []byte(data.Encode()) - } else { - b, err = cf.Marshal(nmsg) - if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) - } - } + b, err := cf.Marshal(nmsg) + if err != nil { + return nil, errors.BadRequest("go.micro.client", err.Error()) } if len(b) > 0 { @@ -145,20 +132,10 @@ func (h *httpClient) call(ctx context.Context, addr string, req client.Request, // set the content type for the request header.Set("Content-Type", ct) - var cf codec.Codec - var err error - // get codec - switch ct { - case "application/x-www-form-urlencoded": - cf, err = h.newCodec(DefaultContentType) - default: - cf, err = h.newCodec(ct) - } - + cf, err := h.newCodec(ct) if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } - hreq, err := newRequest(addr, req, ct, cf, req.Body(), opts) if err != nil { return err @@ -184,7 +161,13 @@ func (h *httpClient) call(ctx context.Context, addr string, req client.Request, defer hrsp.Body.Close() - return parseRsp(ctx, hrsp, cf, rsp, opts) + if ct == "application/x-www-form-urlencoded" { + cf, err = h.newCodec(DefaultContentType) + if err != nil { + return errors.InternalServerError("go.micro.client", err.Error()) + } + } + return h.parseRsp(ctx, hrsp, rsp, opts) } func (h *httpClient) stream(ctx context.Context, addr string, req client.Request, opts client.CallOptions) (client.Stream, error) { diff --git a/stream.go b/stream.go index 83bcf47..f90c3a3 100644 --- a/stream.go +++ b/stream.go @@ -4,6 +4,7 @@ import ( "bufio" "context" "fmt" + "io" "net" "net/http" "sync" @@ -89,7 +90,7 @@ func (h *httpStream) Recv(msg interface{}) error { } defer hrsp.Body.Close() - return parseRsp(h.context, hrsp, h.cf, msg, h.opts) + return h.parseRsp(h.context, hrsp, h.cf, msg, h.opts) } func (h *httpStream) Error() error { @@ -107,3 +108,39 @@ func (h *httpStream) Close() error { return h.conn.Close() } } + +func (h *httpStream) parseRsp(ctx context.Context, hrsp *http.Response, cf codec.Codec, rsp interface{}, opts client.CallOptions) error { + var err error + + // fast path return + if hrsp.StatusCode == http.StatusNoContent { + return nil + } + + if hrsp.StatusCode < 400 { + if err = cf.ReadBody(hrsp.Body, rsp); err != nil { + return errors.InternalServerError("go.micro.client", err.Error()) + } + return nil + } + + errmap, ok := opts.Context.Value(errorMapKey{}).(map[string]interface{}) + if ok && errmap != nil { + if err, ok = errmap[fmt.Sprintf("%d", hrsp.StatusCode)].(error); !ok { + err, ok = errmap["default"].(error) + } + } + if err == nil { + buf, err := io.ReadAll(hrsp.Body) + if err != nil { + errors.InternalServerError("go.micro.client", err.Error()) + } + return errors.New("go.micro.client", string(buf), int32(hrsp.StatusCode)) + } + + if cerr := cf.ReadBody(hrsp.Body, err); cerr != nil { + err = errors.InternalServerError("go.micro.client", cerr.Error()) + } + + return err +} diff --git a/util.go b/util.go index 54ba811..3fd38d9 100644 --- a/util.go +++ b/util.go @@ -3,14 +3,13 @@ package http import ( "context" "fmt" - "io/ioutil" + "io" "net/http" "reflect" "strings" "sync" "github.com/unistack-org/micro/v3/client" - "github.com/unistack-org/micro/v3/codec" "github.com/unistack-org/micro/v3/errors" rutil "github.com/unistack-org/micro/v3/util/reflect" util "github.com/unistack-org/micro/v3/util/router" @@ -159,48 +158,46 @@ func newTemplate(path string) (util.Template, error) { return tpl, nil } -func parseRsp(ctx context.Context, hrsp *http.Response, cf codec.Codec, rsp interface{}, opts client.CallOptions) error { +func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp interface{}, opts client.CallOptions) error { // fast path return if hrsp.StatusCode == http.StatusNoContent { return nil } - b, err := ioutil.ReadAll(hrsp.Body) + ct := DefaultContentType + + if htype := hrsp.Header.Get("Content-Type"); htype != "" { + ct = htype + } + + cf, err := h.newCodec(ct) if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } if hrsp.StatusCode < 400 { - // unmarshal only if body not nil - if len(b) > 0 { - // unmarshal - if err := cf.Unmarshal(b, rsp); err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) - } + if err := cf.ReadBody(hrsp.Body, rsp); err != nil { + return errors.InternalServerError("go.micro.client", err.Error()) } return nil } errmap, ok := opts.Context.Value(errorMapKey{}).(map[string]interface{}) - if !ok || errmap == nil { - // user not provide map of errors - // id: req.Service() ?? - return errors.New("go.micro.client", string(b), int32(hrsp.StatusCode)) - } - - if err, ok = errmap[fmt.Sprintf("%d", hrsp.StatusCode)].(error); !ok { - err, ok = errmap["default"].(error) - } - if !ok { - return errors.New("go.micro.client", string(b), int32(hrsp.StatusCode)) - } - - if len(b) > 0 { - if cerr := cf.Unmarshal(b, err); cerr != nil { - err = errors.InternalServerError("go.micro.client", cerr.Error()) + if ok && errmap != nil { + if err, ok = errmap[fmt.Sprintf("%d", hrsp.StatusCode)].(error); !ok { + err, ok = errmap["default"].(error) } - } else { - err = errors.New("go.micro.client", string(b), int32(hrsp.StatusCode)) + } + if err == nil { + buf, err := io.ReadAll(hrsp.Body) + if err != nil { + errors.InternalServerError("go.micro.client", err.Error()) + } + return errors.New("go.micro.client", string(buf), int32(hrsp.StatusCode)) + } + + if cerr := cf.ReadBody(hrsp.Body, err); cerr != nil { + err = errors.InternalServerError("go.micro.client", cerr.Error()) } return err