// getResponse decodes a http.Response to create a cmds.Response func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error) { var err error res := cmds.NewResponse(req) contentType := httpRes.Header.Get(contentTypeHeader) contentType = strings.Split(contentType, ";")[0] lengthHeader := httpRes.Header.Get(extraContentLengthHeader) if len(lengthHeader) > 0 { length, err := strconv.ParseUint(lengthHeader, 10, 64) if err != nil { return nil, err } res.SetLength(length) } rr := &httpResponseReader{httpRes} res.SetCloser(rr) if contentType != applicationJson { // for all non json output types, just stream back the output res.SetOutput(rr) return res, nil } else if len(httpRes.Header.Get(channelHeader)) > 0 { // if output is coming from a channel, decode each chunk outChan := make(chan interface{}) go readStreamedJson(req, rr, outChan) res.SetOutput((<-chan interface{})(outChan)) return res, nil } dec := json.NewDecoder(rr) // If we ran into an error if httpRes.StatusCode >= http.StatusBadRequest { e := cmds.Error{} switch { case httpRes.StatusCode == http.StatusNotFound: // handle 404s e.Message = "Command not found." e.Code = cmds.ErrClient case contentType == plainText: // handle non-marshalled errors mes, err := ioutil.ReadAll(rr) if err != nil { return nil, err } e.Message = string(mes) e.Code = cmds.ErrNormal default: // handle marshalled errors err = dec.Decode(&e) if err != nil { return nil, err } } res.SetError(e, e.Code) return res, nil } outputType := reflect.TypeOf(req.Command().Type) v, err := decodeTypedVal(outputType, dec) if err != nil && err != io.EOF { return nil, err } res.SetOutput(v) return res, nil }
// getResponse decodes a http.Response to create a cmds.Response func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error) { var err error res := cmds.NewResponse(req) contentType := httpRes.Header.Get(contentTypeHeader) contentType = strings.Split(contentType, ";")[0] lengthHeader := httpRes.Header.Get(contentLengthHeader) if len(lengthHeader) > 0 { length, err := strconv.ParseUint(lengthHeader, 10, 64) if err != nil { return nil, err } res.SetLength(length) } if len(httpRes.Header.Get(streamHeader)) > 0 { // if output is a stream, we can just use the body reader res.SetOutput(httpRes.Body) return res, nil } else if len(httpRes.Header.Get(channelHeader)) > 0 { // if output is coming from a channel, decode each chunk outChan := make(chan interface{}) go func() { dec := json.NewDecoder(httpRes.Body) outputType := reflect.TypeOf(req.Command().Type) ctx := req.Context().Context for { var v interface{} var err error if outputType != nil { v = reflect.New(outputType).Interface() err = dec.Decode(v) } else { err = dec.Decode(&v) } if err != nil && err != io.EOF { fmt.Println(err.Error()) return } select { case <-ctx.Done(): close(outChan) return default: } if err == io.EOF { close(outChan) return } outChan <- v } }() res.SetOutput((<-chan interface{})(outChan)) return res, nil } dec := json.NewDecoder(httpRes.Body) if httpRes.StatusCode >= http.StatusBadRequest { e := cmds.Error{} if httpRes.StatusCode == http.StatusNotFound { // handle 404s e.Message = "Command not found." e.Code = cmds.ErrClient } else if contentType == "text/plain" { // handle non-marshalled errors buf := bytes.NewBuffer(nil) io.Copy(buf, httpRes.Body) e.Message = string(buf.Bytes()) e.Code = cmds.ErrNormal } else { // handle marshalled errors err = dec.Decode(&e) if err != nil { return nil, err } } res.SetError(e, e.Code) } else { outputType := reflect.TypeOf(req.Command().Type) var v interface{} if outputType != nil { v = reflect.New(outputType).Interface() err = dec.Decode(v) } else { err = dec.Decode(&v) } if err != nil && err != io.EOF { return nil, err } if v != nil { res.SetOutput(v) } } return res, nil }