mirror of
https://github.com/safing/portbase
synced 2025-04-16 23:49:09 +00:00
Add support for dsd formats in HTTP
This commit is contained in:
parent
560b96a825
commit
40b25a0af7
1 changed files with 132 additions and 0 deletions
132
formats/dsd/http.go
Normal file
132
formats/dsd/http.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package dsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingBody = errors.New("dsd: missing http body")
|
||||
ErrMissingContentType = errors.New("dsd: missing http content type")
|
||||
)
|
||||
|
||||
const (
|
||||
httpHeaderContentType = "Content-Type"
|
||||
)
|
||||
|
||||
func LoadFromHTTPRequest(r *http.Request, t interface{}) (format uint8, err error) {
|
||||
if r.Body == nil {
|
||||
return 0, ErrMissingBody
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
return loadFromHTTP(r.Body, r.Header.Get(httpHeaderContentType), t)
|
||||
}
|
||||
|
||||
func LoadFromHTTPResponse(resp *http.Response, t interface{}) (format uint8, err error) {
|
||||
if resp.Body == nil {
|
||||
return 0, ErrMissingBody
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return loadFromHTTP(resp.Body, resp.Header.Get(httpHeaderContentType), t)
|
||||
}
|
||||
|
||||
func loadFromHTTP(body io.Reader, mimeType string, t interface{}) (format uint8, err error) {
|
||||
// Read full body.
|
||||
data, err := ioutil.ReadAll(body)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("dsd: failed to read http body: %w", err)
|
||||
}
|
||||
|
||||
// Get mime type from header, then check, clean and verify it.
|
||||
if mimeType == "" {
|
||||
return 0, ErrMissingContentType
|
||||
}
|
||||
if strings.Contains(mimeType, ";") {
|
||||
mimeType = strings.SplitN(mimeType, ";", 2)[0]
|
||||
}
|
||||
format, ok := MimeTypeToFormat[mimeType]
|
||||
if !ok {
|
||||
return 0, ErrIncompatibleFormat
|
||||
}
|
||||
|
||||
// Parse data..
|
||||
return format, LoadAsFormat(data, format, t)
|
||||
}
|
||||
|
||||
func RequestHTTPResponseFormat(r *http.Request, format uint8) (mimeType string, err error) {
|
||||
// Get mime type.
|
||||
mimeType, ok := FormatToMimeType[format]
|
||||
if !ok {
|
||||
return "", ErrIncompatibleFormat
|
||||
}
|
||||
|
||||
// Request response format.
|
||||
r.Header.Set("Accept", mimeType)
|
||||
|
||||
return mimeType, nil
|
||||
}
|
||||
|
||||
func DumpToHTTPRequest(r *http.Request, t interface{}, format uint8) error {
|
||||
mimeType, err := RequestHTTPResponseFormat(r, format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Serialize data.
|
||||
data, err := Dump(t, format)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dsd: failed to serialize: %w", err)
|
||||
}
|
||||
|
||||
// Set body.
|
||||
r.Header.Set("Content-Type", mimeType)
|
||||
r.Body = ioutil.NopCloser(bytes.NewReader(data))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DumpToHTTPResponse(w http.ResponseWriter, r *http.Request, t interface{}, fallbackFormat uint8) error {
|
||||
// Get format from Accept header.
|
||||
format, ok := MimeTypeToFormat[r.Header.Get("Accept")]
|
||||
if !ok {
|
||||
format = fallbackFormat
|
||||
}
|
||||
mimeType, ok := FormatToMimeType[format]
|
||||
if !ok {
|
||||
return ErrIncompatibleFormat
|
||||
}
|
||||
|
||||
// Serialize data.
|
||||
data, err := Dump(t, format)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dsd: failed to serialize: %w", err)
|
||||
}
|
||||
|
||||
// Write data to response
|
||||
w.Header().Set("Content-Type", mimeType)
|
||||
_, err = w.Write(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dsd: failed to write response: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
FormatToMimeType = map[uint8]string{
|
||||
JSON: "application/json; charset=utf-8",
|
||||
CBOR: "application/cbor",
|
||||
MsgPack: "application/msgpack",
|
||||
}
|
||||
MimeTypeToFormat = map[string]uint8{
|
||||
"application/json": JSON,
|
||||
"application/cbor": CBOR,
|
||||
"application/msgpack": MsgPack,
|
||||
}
|
||||
)
|
Loading…
Add table
Reference in a new issue