initial commit

This commit is contained in:
2024-12-29 18:06:39 -05:00
commit fe4b5b6033
73 changed files with 9155 additions and 0 deletions

1
vendor/github.com/go-chi/render/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
vendor

20
vendor/github.com/go-chi/render/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright (c) 2016-Present https://github.com/go-chi authors
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

27
vendor/github.com/go-chi/render/README.md generated vendored Normal file
View File

@@ -0,0 +1,27 @@
# render
![tests](https://github.com/go-chi/render/actions/workflows/test.yml/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-chi/render)](https://goreportcard.com/report/github.com/go-chi/render)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-chi/render.svg)](https://pkg.go.dev/github.com/go-chi/render)
The `render` package helps manage HTTP request / response payloads.
Every well-designed, robust and maintainable Web Service / REST API also needs
well-*defined* request and response payloads. Together with the endpoint handlers,
the request and response payloads make up the contract between your server and the
clients calling on it.
Typically in a REST API application, you will have your data models (objects/structs)
that hold lower-level runtime application state, and at times you need to assemble,
decorate, hide or transform the representation before responding to a client. That
server output (response payload) structure, is also likely the input structure to
another handler on the server.
This is where `render` comes in - offering a few simple helpers and interfaces to
provide a simple pattern for managing payload encoding and decoding.
We've also combined it with some helpers for responding to content types and parsing
request bodies. Please have a look at the [rest](https://github.com/go-chi/chi/blob/master/_examples/rest/main.go)
example which uses the latest chi/render sub-pkg.
All feedback is welcome, thank you!

84
vendor/github.com/go-chi/render/content_type.go generated vendored Normal file
View File

@@ -0,0 +1,84 @@
package render
import (
"context"
"net/http"
"strings"
)
var (
ContentTypeCtxKey = &contextKey{"ContentType"}
)
// ContentType is an enumeration of common HTTP content types.
type ContentType int
// ContentTypes handled by this package.
const (
ContentTypeUnknown ContentType = iota
ContentTypePlainText
ContentTypeHTML
ContentTypeJSON
ContentTypeXML
ContentTypeForm
ContentTypeEventStream
)
func GetContentType(s string) ContentType {
s = strings.TrimSpace(strings.Split(s, ";")[0])
switch s {
case "text/plain":
return ContentTypePlainText
case "text/html", "application/xhtml+xml":
return ContentTypeHTML
case "application/json", "text/javascript":
return ContentTypeJSON
case "text/xml", "application/xml":
return ContentTypeXML
case "application/x-www-form-urlencoded":
return ContentTypeForm
case "text/event-stream":
return ContentTypeEventStream
default:
return ContentTypeUnknown
}
}
// SetContentType is a middleware that forces response Content-Type.
func SetContentType(contentType ContentType) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
r = r.WithContext(context.WithValue(r.Context(), ContentTypeCtxKey, contentType))
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
}
// GetRequestContentType is a helper function that returns ContentType based on
// context or request headers.
func GetRequestContentType(r *http.Request) ContentType {
if contentType, ok := r.Context().Value(ContentTypeCtxKey).(ContentType); ok {
return contentType
}
return GetContentType(r.Header.Get("Content-Type"))
}
func GetAcceptedContentType(r *http.Request) ContentType {
if contentType, ok := r.Context().Value(ContentTypeCtxKey).(ContentType); ok {
return contentType
}
var contentType ContentType
// Parse request Accept header.
fields := strings.Split(r.Header.Get("Accept"), ",")
if len(fields) > 0 {
contentType = GetContentType(strings.TrimSpace(fields[0]))
}
if contentType == ContentTypeUnknown {
contentType = ContentTypePlainText
}
return contentType
}

57
vendor/github.com/go-chi/render/decoder.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package render
import (
"encoding/json"
"encoding/xml"
"errors"
"io"
"io/ioutil"
"net/http"
"github.com/ajg/form"
)
// Decode is a package-level variable set to our default Decoder. We do this
// because it allows you to set render.Decode to another function with the
// same function signature, while also utilizing the render.Decoder() function
// itself. Effectively, allowing you to easily add your own logic to the package
// defaults. For example, maybe you want to impose a limit on the number of
// bytes allowed to be read from the request body.
var Decode = DefaultDecoder
// DefaultDecoder detects the correct decoder for use on an HTTP request and
// marshals into a given interface.
func DefaultDecoder(r *http.Request, v interface{}) error {
var err error
switch GetRequestContentType(r) {
case ContentTypeJSON:
err = DecodeJSON(r.Body, v)
case ContentTypeXML:
err = DecodeXML(r.Body, v)
case ContentTypeForm:
err = DecodeForm(r.Body, v)
default:
err = errors.New("render: unable to automatically decode the request content type")
}
return err
}
// DecodeJSON decodes a given reader into an interface using the json decoder.
func DecodeJSON(r io.Reader, v interface{}) error {
defer io.Copy(ioutil.Discard, r) //nolint:errcheck
return json.NewDecoder(r).Decode(v)
}
// DecodeXML decodes a given reader into an interface using the xml decoder.
func DecodeXML(r io.Reader, v interface{}) error {
defer io.Copy(ioutil.Discard, r) //nolint:errcheck
return xml.NewDecoder(r).Decode(v)
}
// DecodeForm decodes a given reader into an interface using the form decoder.
func DecodeForm(r io.Reader, v interface{}) error {
decoder := form.NewDecoder(r) //nolint:errcheck
return decoder.Decode(v)
}

143
vendor/github.com/go-chi/render/render.go generated vendored Normal file
View File

@@ -0,0 +1,143 @@
package render
import (
"net/http"
"reflect"
)
// Renderer interface for managing response payloads.
type Renderer interface {
Render(w http.ResponseWriter, r *http.Request) error
}
// Binder interface for managing request payloads.
type Binder interface {
Bind(r *http.Request) error
}
// Bind decodes a request body and executes the Binder method of the
// payload structure.
func Bind(r *http.Request, v Binder) error {
if err := Decode(r, v); err != nil {
return err
}
return binder(r, v)
}
// Render renders a single payload and respond to the client request.
func Render(w http.ResponseWriter, r *http.Request, v Renderer) error {
if err := renderer(w, r, v); err != nil {
return err
}
Respond(w, r, v)
return nil
}
// RenderList renders a slice of payloads and responds to the client request.
func RenderList(w http.ResponseWriter, r *http.Request, l []Renderer) error {
for _, v := range l {
if err := renderer(w, r, v); err != nil {
return err
}
}
Respond(w, r, l)
return nil
}
func isNil(f reflect.Value) bool {
switch f.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return f.IsNil()
default:
return false
}
}
// Executed top-down
func renderer(w http.ResponseWriter, r *http.Request, v Renderer) error {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
// We call it top-down.
if err := v.Render(w, r); err != nil {
return err
}
// We're done if the Renderer isn't a struct object
if rv.Kind() != reflect.Struct {
return nil
}
// For structs, we call Render on each field that implements Renderer
for i := 0; i < rv.NumField(); i++ {
f := rv.Field(i)
if f.Type().Implements(rendererType) {
if isNil(f) {
continue
}
fv := f.Interface().(Renderer)
if err := renderer(w, r, fv); err != nil {
return err
}
}
}
return nil
}
// Executed bottom-up
func binder(r *http.Request, v Binder) error {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
// Call Binder on non-struct types right away
if rv.Kind() != reflect.Struct {
return v.Bind(r)
}
// For structs, we call Bind on each field that implements Binder
for i := 0; i < rv.NumField(); i++ {
f := rv.Field(i)
if f.Type().Implements(binderType) {
if isNil(f) {
continue
}
fv := f.Interface().(Binder)
if err := binder(r, fv); err != nil {
return err
}
}
}
// We call it bottom-up
if err := v.Bind(r); err != nil {
return err
}
return nil
}
var (
rendererType = reflect.TypeOf(new(Renderer)).Elem()
binderType = reflect.TypeOf(new(Binder)).Elem()
)
// contextKey is a value for use with context.WithValue. It's used as
// a pointer so it fits in an interface{} without allocation. This technique
// for defining context keys was copied from Go 1.7's new use of context in net/http.
type contextKey struct {
name string
}
func (k *contextKey) String() string {
return "chi render context value " + k.name
}

234
vendor/github.com/go-chi/render/responder.go generated vendored Normal file
View File

@@ -0,0 +1,234 @@
package render
import (
"bytes"
"context"
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
"reflect"
)
// M is a convenience alias for quickly building a map structure that is going
// out to a responder. Just a short-hand.
type M map[string]interface{}
// Respond is a package-level variable set to our default Responder. We do this
// because it allows you to set render.Respond to another function with the
// same function signature, while also utilizing the render.Responder() function
// itself. Effectively, allowing you to easily add your own logic to the package
// defaults. For example, maybe you want to test if v is an error and respond
// differently, or log something before you respond.
var Respond = DefaultResponder
// StatusCtxKey is a context key to record a future HTTP response status code.
var StatusCtxKey = &contextKey{"Status"}
// Status sets a HTTP response status code hint into request context at any point
// during the request life-cycle. Before the Responder sends its response header
// it will check the StatusCtxKey
func Status(r *http.Request, status int) {
*r = *r.WithContext(context.WithValue(r.Context(), StatusCtxKey, status))
}
// Respond handles streaming JSON and XML responses, automatically setting the
// Content-Type based on request headers. It will default to a JSON response.
func DefaultResponder(w http.ResponseWriter, r *http.Request, v interface{}) {
if v != nil {
switch reflect.TypeOf(v).Kind() {
case reflect.Chan:
switch GetAcceptedContentType(r) {
case ContentTypeEventStream:
channelEventStream(w, r, v)
return
default:
v = channelIntoSlice(w, r, v)
}
}
}
// Format response based on request Accept header.
switch GetAcceptedContentType(r) {
case ContentTypeJSON:
JSON(w, r, v)
case ContentTypeXML:
XML(w, r, v)
default:
JSON(w, r, v)
}
}
// PlainText writes a string to the response, setting the Content-Type as
// text/plain.
func PlainText(w http.ResponseWriter, r *http.Request, v string) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write([]byte(v)) //nolint:errcheck
}
// Data writes raw bytes to the response, setting the Content-Type as
// application/octet-stream.
func Data(w http.ResponseWriter, r *http.Request, v []byte) {
w.Header().Set("Content-Type", "application/octet-stream")
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write(v) //nolint:errcheck
}
// HTML writes a string to the response, setting the Content-Type as text/html.
func HTML(w http.ResponseWriter, r *http.Request, v string) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write([]byte(v)) //nolint:errcheck
}
// JSON marshals 'v' to JSON, automatically escaping HTML and setting the
// Content-Type as application/json.
func JSON(w http.ResponseWriter, r *http.Request, v interface{}) {
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(true)
if err := enc.Encode(v); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write(buf.Bytes()) //nolint:errcheck
}
// XML marshals 'v' to XML, setting the Content-Type as application/xml. It
// will automatically prepend a generic XML header (see encoding/xml.Header) if
// one is not found in the first 100 bytes of 'v'.
func XML(w http.ResponseWriter, r *http.Request, v interface{}) {
b, err := xml.Marshal(v)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
// Try to find <?xml header in first 100 bytes (just in case there're some XML comments).
findHeaderUntil := len(b)
if findHeaderUntil > 100 {
findHeaderUntil = 100
}
if !bytes.Contains(b[:findHeaderUntil], []byte("<?xml")) {
// No header found. Print it out first.
w.Write([]byte(xml.Header)) //nolint:errcheck
}
w.Write(b) //nolint:errcheck
}
// NoContent returns a HTTP 204 "No Content" response.
func NoContent(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) {
if reflect.TypeOf(v).Kind() != reflect.Chan {
panic(fmt.Sprintf("render: event stream expects a channel, not %v", reflect.TypeOf(v).Kind()))
}
w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
w.Header().Set("Cache-Control", "no-cache")
if r.ProtoMajor == 1 {
// An endpoint MUST NOT generate an HTTP/2 message containing connection-specific header fields.
// Source: RFC7540
w.Header().Set("Connection", "keep-alive")
}
w.WriteHeader(http.StatusOK)
ctx := r.Context()
for {
switch chosen, recv, ok := reflect.Select([]reflect.SelectCase{
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ctx.Done())},
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(v)},
}); chosen {
case 0: // equivalent to: case <-ctx.Done()
w.Write([]byte("event: error\ndata: {\"error\":\"Server Timeout\"}\n\n")) //nolint:errcheck
return
default: // equivalent to: case v, ok := <-stream
if !ok {
w.Write([]byte("event: EOF\n\n")) //nolint:errcheck
return
}
v := recv.Interface()
// Build each channel item.
if rv, ok := v.(Renderer); ok {
err := renderer(w, r, rv)
if err != nil {
v = err
} else {
v = rv
}
}
bytes, err := json.Marshal(v)
if err != nil {
w.Write([]byte(fmt.Sprintf("event: error\ndata: {\"error\":\"%v\"}\n\n", err))) //nolint:errcheck
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
continue
}
w.Write([]byte(fmt.Sprintf("event: data\ndata: %s\n\n", bytes))) //nolint:errcheck
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
}
}
}
// channelIntoSlice buffers channel data into a slice.
func channelIntoSlice(w http.ResponseWriter, r *http.Request, from interface{}) interface{} {
ctx := r.Context()
var to []interface{}
for {
switch chosen, recv, ok := reflect.Select([]reflect.SelectCase{
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ctx.Done())},
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(from)},
}); chosen {
case 0: // equivalent to: case <-ctx.Done()
http.Error(w, "Server Timeout", http.StatusGatewayTimeout)
return nil
default: // equivalent to: case v, ok := <-stream
if !ok {
return to
}
v := recv.Interface()
// Render each channel item.
if rv, ok := v.(Renderer); ok {
err := renderer(w, r, rv)
if err != nil {
v = err
} else {
v = rv
}
}
to = append(to, v)
}
}
}