Skip to content
Snippets Groups Projects
http.go 2.2 KiB
Newer Older
package flamenco

import (
	"encoding/json"
	"fmt"
	"io"

	log "github.com/Sirupsen/logrus"
)

/**
 * Decodes JSON and writes a Bad Request status if it fails.
 */
func DecodeJson(w http.ResponseWriter, r io.Reader, document interface{},
	logprefix string) error {
	dec := json.NewDecoder(r)

	if err := dec.Decode(document); err != nil {
		log.Printf("%s Unable to decode JSON: %s", logprefix, err)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Unable to decode JSON: %s\n", err)
		return err
	}

	return nil
}

/**
 * Sends a JSON document to some URL via HTTP.
 * :param tweakrequest: can be used to tweak the request before sending it, for
 *    example by adding authentication headers. May be nil.
 * :param responsehandler: is called when a non-error response has been read.
 *    May be nil.
 */
func SendJson(logprefix, method string, url *url.URL,
	payload interface{},
	tweakrequest func(req *http.Request),
	responsehandler func(resp *http.Response, body []byte) error,
) error {
	payload_bytes, err := json.Marshal(payload)
	if err != nil {
		log.Printf("%s: ERROR: Unable to marshal JSON: %s\n", logprefix, err)
		return err
	}

	// TODO Sybren: enable GZip compression.
	req, err := http.NewRequest("POST", url.String(), bytes.NewBuffer(payload_bytes))
	if err != nil {
		log.Printf("%s: ERROR: Unable to create request: %s\n", logprefix, err)
		return err
	}
	req.Header.Add("Content-Type", "application/json")
	if tweakrequest != nil {
		tweakrequest(req)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("%s: ERROR: Unable to POST to %s: %s\n", logprefix, url, err)
		return err
	}

	body, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		log.Printf("%s: ERROR: Error %d POSTing to %s: %s\n",
			logprefix, resp.StatusCode, url, err)
		return err
	}

	if resp.StatusCode >= 300 {
		log.Printf("%s: ERROR: Error %d POSTing to %s\n",
			logprefix, resp.StatusCode, url)
		if resp.StatusCode != 404 {
			log.Printf("    body:\n%s\n", body)
		}
		return fmt.Errorf("%s: Error %d POSTing to %s", logprefix, resp.StatusCode, url)
	}

	if responsehandler != nil {
		return responsehandler(resp, body)
	}

	return nil
}