mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-04-11 18:13:00 +00:00
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
260 lines
10 KiB
Go
260 lines
10 KiB
Go
package restful
|
|
|
|
// Copyright 2013 Ernest Micklei. All rights reserved.
|
|
// Use of this source code is governed by a license
|
|
// that can be found in the LICENSE file.
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"net"
|
|
"net/http"
|
|
)
|
|
|
|
// DefaultResponseMimeType is DEPRECATED, use DefaultResponseContentType(mime)
|
|
var DefaultResponseMimeType string
|
|
|
|
//PrettyPrintResponses controls the indentation feature of XML and JSON serialization
|
|
var PrettyPrintResponses = true
|
|
|
|
// Response is a wrapper on the actual http ResponseWriter
|
|
// It provides several convenience methods to prepare and write response content.
|
|
type Response struct {
|
|
http.ResponseWriter
|
|
requestAccept string // mime-type what the Http Request says it wants to receive
|
|
routeProduces []string // mime-types what the Route says it can produce
|
|
statusCode int // HTTP status code that has been written explicitly (if zero then net/http has written 200)
|
|
contentLength int // number of bytes written for the response body
|
|
prettyPrint bool // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses.
|
|
err error // err property is kept when WriteError is called
|
|
hijacker http.Hijacker // if underlying ResponseWriter supports it
|
|
}
|
|
|
|
// NewResponse creates a new response based on a http ResponseWriter.
|
|
func NewResponse(httpWriter http.ResponseWriter) *Response {
|
|
hijacker, _ := httpWriter.(http.Hijacker)
|
|
return &Response{ResponseWriter: httpWriter, routeProduces: []string{}, statusCode: http.StatusOK, prettyPrint: PrettyPrintResponses, hijacker: hijacker}
|
|
}
|
|
|
|
// DefaultResponseContentType set a default.
|
|
// If Accept header matching fails, fall back to this type.
|
|
// Valid values are restful.MIME_JSON and restful.MIME_XML
|
|
// Example:
|
|
// restful.DefaultResponseContentType(restful.MIME_JSON)
|
|
func DefaultResponseContentType(mime string) {
|
|
DefaultResponseMimeType = mime
|
|
}
|
|
|
|
// InternalServerError writes the StatusInternalServerError header.
|
|
// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason)
|
|
func (r Response) InternalServerError() Response {
|
|
r.WriteHeader(http.StatusInternalServerError)
|
|
return r
|
|
}
|
|
|
|
// Hijack implements the http.Hijacker interface. This expands
|
|
// the Response to fulfill http.Hijacker if the underlying
|
|
// http.ResponseWriter supports it.
|
|
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
if r.hijacker == nil {
|
|
return nil, nil, errors.New("http.Hijacker not implemented by underlying http.ResponseWriter")
|
|
}
|
|
return r.hijacker.Hijack()
|
|
}
|
|
|
|
// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output.
|
|
func (r *Response) PrettyPrint(bePretty bool) {
|
|
r.prettyPrint = bePretty
|
|
}
|
|
|
|
// AddHeader is a shortcut for .Header().Add(header,value)
|
|
func (r Response) AddHeader(header string, value string) Response {
|
|
r.Header().Add(header, value)
|
|
return r
|
|
}
|
|
|
|
// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing.
|
|
func (r *Response) SetRequestAccepts(mime string) {
|
|
r.requestAccept = mime
|
|
}
|
|
|
|
// EntityWriter returns the registered EntityWriter that the entity (requested resource)
|
|
// can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say.
|
|
// If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable.
|
|
func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
|
|
sorted := sortedMimes(r.requestAccept)
|
|
for _, eachAccept := range sorted {
|
|
for _, eachProduce := range r.routeProduces {
|
|
if eachProduce == eachAccept.media {
|
|
if w, ok := entityAccessRegistry.accessorAt(eachAccept.media); ok {
|
|
return w, true
|
|
}
|
|
}
|
|
}
|
|
if eachAccept.media == "*/*" {
|
|
for _, each := range r.routeProduces {
|
|
if w, ok := entityAccessRegistry.accessorAt(each); ok {
|
|
return w, true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// if requestAccept is empty
|
|
writer, ok := entityAccessRegistry.accessorAt(r.requestAccept)
|
|
if !ok {
|
|
// if not registered then fallback to the defaults (if set)
|
|
if DefaultResponseMimeType == MIME_JSON {
|
|
return entityAccessRegistry.accessorAt(MIME_JSON)
|
|
}
|
|
if DefaultResponseMimeType == MIME_XML {
|
|
return entityAccessRegistry.accessorAt(MIME_XML)
|
|
}
|
|
if DefaultResponseMimeType == MIME_ZIP {
|
|
return entityAccessRegistry.accessorAt(MIME_ZIP)
|
|
}
|
|
// Fallback to whatever the route says it can produce.
|
|
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
|
for _, each := range r.routeProduces {
|
|
if w, ok := entityAccessRegistry.accessorAt(each); ok {
|
|
return w, true
|
|
}
|
|
}
|
|
if trace {
|
|
traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept)
|
|
}
|
|
}
|
|
return writer, ok
|
|
}
|
|
|
|
// WriteEntity calls WriteHeaderAndEntity with Http Status OK (200)
|
|
func (r *Response) WriteEntity(value interface{}) error {
|
|
return r.WriteHeaderAndEntity(http.StatusOK, value)
|
|
}
|
|
|
|
// WriteHeaderAndEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters.
|
|
// If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces.
|
|
// If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
|
|
// If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead.
|
|
// If there is no writer available that can represent the value in the requested MIME type then Http Status NotAcceptable is written.
|
|
// Current implementation ignores any q-parameters in the Accept Header.
|
|
// Returns an error if the value could not be written on the response.
|
|
func (r *Response) WriteHeaderAndEntity(status int, value interface{}) error {
|
|
writer, ok := r.EntityWriter()
|
|
if !ok {
|
|
r.WriteHeader(http.StatusNotAcceptable)
|
|
return nil
|
|
}
|
|
return writer.Write(r, status, value)
|
|
}
|
|
|
|
// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
|
|
// It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter.
|
|
func (r *Response) WriteAsXml(value interface{}) error {
|
|
return writeXML(r, http.StatusOK, MIME_XML, value)
|
|
}
|
|
|
|
// WriteHeaderAndXml is a convenience method for writing a status and value in xml (requires Xml tags on the value)
|
|
// It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter.
|
|
func (r *Response) WriteHeaderAndXml(status int, value interface{}) error {
|
|
return writeXML(r, status, MIME_XML, value)
|
|
}
|
|
|
|
// WriteAsJson is a convenience method for writing a value in json.
|
|
// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
|
|
func (r *Response) WriteAsJson(value interface{}) error {
|
|
return writeJSON(r, http.StatusOK, MIME_JSON, value)
|
|
}
|
|
|
|
// WriteJson is a convenience method for writing a value in Json with a given Content-Type.
|
|
// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
|
|
func (r *Response) WriteJson(value interface{}, contentType string) error {
|
|
return writeJSON(r, http.StatusOK, contentType, value)
|
|
}
|
|
|
|
// WriteHeaderAndJson is a convenience method for writing the status and a value in Json with a given Content-Type.
|
|
// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
|
|
func (r *Response) WriteHeaderAndJson(status int, value interface{}, contentType string) error {
|
|
return writeJSON(r, status, contentType, value)
|
|
}
|
|
|
|
// WriteError writes the http status and the error string on the response. err can be nil.
|
|
// Return an error if writing was not successful.
|
|
func (r *Response) WriteError(httpStatus int, err error) (writeErr error) {
|
|
r.err = err
|
|
if err == nil {
|
|
writeErr = r.WriteErrorString(httpStatus, "")
|
|
} else {
|
|
writeErr = r.WriteErrorString(httpStatus, err.Error())
|
|
}
|
|
return writeErr
|
|
}
|
|
|
|
// WriteServiceError is a convenience method for a responding with a status and a ServiceError
|
|
func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
|
|
r.err = err
|
|
return r.WriteHeaderAndEntity(httpStatus, err)
|
|
}
|
|
|
|
// WriteErrorString is a convenience method for an error status with the actual error
|
|
func (r *Response) WriteErrorString(httpStatus int, errorReason string) error {
|
|
if r.err == nil {
|
|
// if not called from WriteError
|
|
r.err = errors.New(errorReason)
|
|
}
|
|
r.WriteHeader(httpStatus)
|
|
if _, err := r.Write([]byte(errorReason)); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Flush implements http.Flusher interface, which sends any buffered data to the client.
|
|
func (r *Response) Flush() {
|
|
if f, ok := r.ResponseWriter.(http.Flusher); ok {
|
|
f.Flush()
|
|
} else if trace {
|
|
traceLogger.Printf("ResponseWriter %v doesn't support Flush", r)
|
|
}
|
|
}
|
|
|
|
// WriteHeader is overridden to remember the Status Code that has been written.
|
|
// Changes to the Header of the response have no effect after this.
|
|
func (r *Response) WriteHeader(httpStatus int) {
|
|
r.statusCode = httpStatus
|
|
r.ResponseWriter.WriteHeader(httpStatus)
|
|
}
|
|
|
|
// StatusCode returns the code that has been written using WriteHeader.
|
|
func (r Response) StatusCode() int {
|
|
if 0 == r.statusCode {
|
|
// no status code has been written yet; assume OK
|
|
return http.StatusOK
|
|
}
|
|
return r.statusCode
|
|
}
|
|
|
|
// Write writes the data to the connection as part of an HTTP reply.
|
|
// Write is part of http.ResponseWriter interface.
|
|
func (r *Response) Write(bytes []byte) (int, error) {
|
|
written, err := r.ResponseWriter.Write(bytes)
|
|
r.contentLength += written
|
|
return written, err
|
|
}
|
|
|
|
// ContentLength returns the number of bytes written for the response content.
|
|
// Note that this value is only correct if all data is written through the Response using its Write* methods.
|
|
// Data written directly using the underlying http.ResponseWriter is not accounted for.
|
|
func (r Response) ContentLength() int {
|
|
return r.contentLength
|
|
}
|
|
|
|
// CloseNotify is part of http.CloseNotifier interface
|
|
func (r Response) CloseNotify() <-chan bool {
|
|
return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
|
}
|
|
|
|
// Error returns the err created by WriteError
|
|
func (r Response) Error() error {
|
|
return r.err
|
|
}
|