mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
Former-commit-id: bd6e0eb0508fb27aea2ff79ad3a82c0acdd51eb7
This commit is contained in:
parent
53b2a22579
commit
f3162254a0
21
HISTORY.md
21
HISTORY.md
|
@ -21,11 +21,32 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
||||||
|
|
||||||
**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris@v11.2.0`.
|
**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris@v11.2.0`.
|
||||||
|
|
||||||
|
|
||||||
# We, 24 July 2019 | v11.2.1
|
# We, 24 July 2019 | v11.2.1
|
||||||
|
|
||||||
- https://github.com/kataras/iris/issues/1298
|
- https://github.com/kataras/iris/issues/1298
|
||||||
- https://github.com/kataras/iris/issues/1207
|
- https://github.com/kataras/iris/issues/1207
|
||||||
|
|
||||||
|
## v11.2.2
|
||||||
|
|
||||||
|
Sessions as middleware:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/kataras/iris/sessions"
|
||||||
|
// [...]
|
||||||
|
|
||||||
|
app := iris.New()
|
||||||
|
sess := sessions.New(sessions.Config{...})
|
||||||
|
|
||||||
|
app.Get("/path", func(ctx iris.Context){
|
||||||
|
session := sessions.Get(ctx)
|
||||||
|
// [work with session...]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- Add `Session.Len() int` to return the total number of stored values/entries.
|
||||||
|
- Make `Context.HTML` and `Context.Text` to accept an optional, variadic, `args ...interface{}` input arg(s) too.
|
||||||
|
|
||||||
# Tu, 23 July 2019 | v11.2.0
|
# Tu, 23 July 2019 | v11.2.0
|
||||||
|
|
||||||
Read about the new release at: https://dev.to/kataras/iris-version-11-2-released-22bc
|
Read about the new release at: https://dev.to/kataras/iris-version-11-2-released-22bc
|
||||||
|
|
|
@ -8,9 +8,11 @@ func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
||||||
body, err := ctx.GetBody()
|
// body, err := ioutil.ReadAll(ctx.Request().Body) once or
|
||||||
|
body, err := ctx.GetBody() // as many times as you need.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Writef("error while reading the requested body: %v", err)
|
ctx.StatusCode(iris.StatusInternalServerError)
|
||||||
|
ctx.WriteString(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1743,12 +1743,29 @@ func (ctx *context) Header(name string, value string) {
|
||||||
ctx.writer.Header().Add(name, value)
|
ctx.writer.Header().Add(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contentTypeContextKey = "_iris_content_type"
|
||||||
|
|
||||||
|
func (ctx *context) contentTypeOnce(cType string, charset string) {
|
||||||
|
if charset == "" {
|
||||||
|
charset = ctx.Application().ConfigurationReadOnly().GetCharset()
|
||||||
|
}
|
||||||
|
|
||||||
|
cType += "; charset=" + charset
|
||||||
|
|
||||||
|
ctx.Values().Set(contentTypeContextKey, cType)
|
||||||
|
ctx.writer.Header().Set(ContentTypeHeaderKey, cType)
|
||||||
|
}
|
||||||
|
|
||||||
// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
|
// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
|
||||||
func (ctx *context) ContentType(cType string) {
|
func (ctx *context) ContentType(cType string) {
|
||||||
if cType == "" {
|
if cType == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, wroteOnce := ctx.Values().GetEntry(contentTypeContextKey); wroteOnce {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 1. if it's path or a filename or an extension,
|
// 1. if it's path or a filename or an extension,
|
||||||
// then take the content type from that
|
// then take the content type from that
|
||||||
if strings.Contains(cType, ".") {
|
if strings.Contains(cType, ".") {
|
||||||
|
@ -2014,20 +2031,19 @@ func (ctx *context) form() (form map[string][]string, found bool) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bodyCopy []byte
|
|
||||||
keepBody = ctx.Application().ConfigurationReadOnly().GetDisableBodyConsumptionOnUnmarshal()
|
keepBody = ctx.Application().ConfigurationReadOnly().GetDisableBodyConsumptionOnUnmarshal()
|
||||||
|
bodyCopy []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
if keepBody {
|
if keepBody {
|
||||||
// on POST, PUT and PATCH it will read the form values from request body otherwise from URL queries.
|
// on POST, PUT and PATCH it will read the form values from request body otherwise from URL queries.
|
||||||
if m := ctx.Method(); m == "POST" || m == "PUT" || m == "PATCH" {
|
if m := ctx.Method(); m == "POST" || m == "PUT" || m == "PATCH" {
|
||||||
body, err := ioutil.ReadAll(ctx.request.Body)
|
bodyCopy, _ = ctx.GetBody()
|
||||||
if err != nil {
|
if len(bodyCopy) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
// ctx.request.Body = ioutil.NopCloser(io.TeeReader(ctx.request.Body, buf))
|
||||||
bodyCopy = body
|
} else {
|
||||||
} else { // else we don't need this behavior.
|
|
||||||
keepBody = false
|
keepBody = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2036,11 +2052,13 @@ func (ctx *context) form() (form map[string][]string, found bool) {
|
||||||
// therefore we don't need to call it here, although it doesn't hurt.
|
// therefore we don't need to call it here, although it doesn't hurt.
|
||||||
// After one call to ParseMultipartForm or ParseForm,
|
// After one call to ParseMultipartForm or ParseForm,
|
||||||
// subsequent calls have no effect, are idempotent.
|
// subsequent calls have no effect, are idempotent.
|
||||||
ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
|
err := ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
|
||||||
|
|
||||||
if keepBody {
|
if keepBody {
|
||||||
ctx.request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyCopy))
|
ctx.request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyCopy))
|
||||||
}
|
}
|
||||||
|
if err != nil && err != http.ErrNotMultipart {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
if form := ctx.request.Form; len(form) > 0 {
|
if form := ctx.request.Form; len(form) > 0 {
|
||||||
return form, true
|
return form, true
|
||||||
|
@ -2863,12 +2881,138 @@ const (
|
||||||
ContentTextHeaderValue = "text/plain"
|
ContentTextHeaderValue = "text/plain"
|
||||||
// ContentXMLHeaderValue header value for XML data.
|
// ContentXMLHeaderValue header value for XML data.
|
||||||
ContentXMLHeaderValue = "text/xml"
|
ContentXMLHeaderValue = "text/xml"
|
||||||
|
// ContentXMLUnreadableHeaderValue obselete header value for XML.
|
||||||
|
ContentXMLUnreadableHeaderValue = "application/xml"
|
||||||
// ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
|
// ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
|
||||||
ContentMarkdownHeaderValue = "text/markdown"
|
ContentMarkdownHeaderValue = "text/markdown"
|
||||||
// ContentYAMLHeaderValue header value for YAML data.
|
// ContentYAMLHeaderValue header value for YAML data.
|
||||||
ContentYAMLHeaderValue = "application/x-yaml"
|
ContentYAMLHeaderValue = "application/x-yaml"
|
||||||
|
// ContentFormHeaderValue header value for post form data.
|
||||||
|
ContentFormHeaderValue = "application/x-www-form-urlencoded"
|
||||||
|
// ContentFormMultipartHeaderValue header value for post multipart form data.
|
||||||
|
ContentFormMultipartHeaderValue = "multipart/form-data"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// const negotitationContextKey = "_iris_accept_negotitation_builder"
|
||||||
|
|
||||||
|
// func (ctx *context) Accept() *Negotitation {
|
||||||
|
// if n := ctx.Values().Get(negotitationContextKey); n != nil {
|
||||||
|
// return n.(*Negotitation)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// n := new(Negotitation)
|
||||||
|
// n.accept = parseHeader(ctx.GetHeader("Accept"))
|
||||||
|
// n.charset = parseHeader(ctx.GetHeader("Accept-Charset"))
|
||||||
|
|
||||||
|
// ctx.Values().Set(negotitationContextKey, n)
|
||||||
|
// return n
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func parseHeader(headerValue string) []string {
|
||||||
|
// in := strings.Split(headerValue, ",")
|
||||||
|
// out := make([]string, 0, len(in))
|
||||||
|
|
||||||
|
// for _, value := range in {
|
||||||
|
// // remove any spaces and quality values such as ;q=0.8.
|
||||||
|
// // */* or * means accept everything.
|
||||||
|
// v := strings.TrimSpace(strings.Split(value, ";")[0])
|
||||||
|
// if v != "" {
|
||||||
|
// out = append(out, v)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return out
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Negotitation builds the accepted mime types and charset
|
||||||
|
// //
|
||||||
|
// // and "Accept-Charset" headers respectfully.
|
||||||
|
// // The default values are set by the client side, server can append or override those.
|
||||||
|
// // The end result will be challenged with runtime preffered set of content types and charsets.
|
||||||
|
// //
|
||||||
|
// // See `Negotitate`.
|
||||||
|
// type Negotitation struct {
|
||||||
|
// // initialized with "Accept" header values.
|
||||||
|
// accept []string
|
||||||
|
// // initialized with "Accept-Charset" and if was empty then the
|
||||||
|
// // application's default (which defaults to utf-8).
|
||||||
|
// charset []string
|
||||||
|
|
||||||
|
// // To support override in request life cycle.
|
||||||
|
// // We need slice when data is the same format
|
||||||
|
// // for one or more mime types,
|
||||||
|
// // i.e text/xml and obselete application/xml.
|
||||||
|
// lastAccept []string
|
||||||
|
// lastCharset []string
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) Override() *Negotitation {
|
||||||
|
// // when called first.
|
||||||
|
// n.accept = n.accept[0:0]
|
||||||
|
// n.charset = n.charset[0:0]
|
||||||
|
|
||||||
|
// // when called after.
|
||||||
|
// if len(n.lastAccept) > 0 {
|
||||||
|
// n.accept = append(n.accept, n.lastAccept...)
|
||||||
|
// n.lastAccept = n.lastAccept[0:0]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if len(n.lastCharset) > 0 {
|
||||||
|
// n.charset = append(n.charset, n.lastCharset...)
|
||||||
|
// n.lastCharset = n.lastCharset[0:0]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return n
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) MIME(mimeType ...string) *Negotitation {
|
||||||
|
// n.lastAccept = mimeType
|
||||||
|
// n.accept = append(n.accept, mimeType...)
|
||||||
|
// return n
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) JSON() *Negotitation {
|
||||||
|
// return n.MIME(ContentJSONHeaderValue)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) XML() *Negotitation {
|
||||||
|
// return n.MIME(ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) HTML() *Negotitation {
|
||||||
|
// return n.MIME(ContentHTMLHeaderValue)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) Charset(charset ...string) *Negotitation {
|
||||||
|
// n.lastCharset = charset
|
||||||
|
// n.charset = append(n.charset, charset...)
|
||||||
|
|
||||||
|
// return n
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *Negotitation) build(preferences []string) (contentType, charset string) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // https://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html
|
||||||
|
// // https://developer.mozilla.org/en-US/docs/tag/Content%20Negotiation
|
||||||
|
// // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
|
||||||
|
// // https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation/List_of_default_Accept_values
|
||||||
|
// func (ctx *context) Negotiate(v interface{}, preferences ...string) (int, error) {
|
||||||
|
// contentType, charset := ctx.Accept().build(preferences)
|
||||||
|
|
||||||
|
// // // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset
|
||||||
|
// // If the server cannot serve any matching character set,
|
||||||
|
// // it can theoretically send back a 406 (Not Acceptable) error code.
|
||||||
|
// ctx.contentTypeOnce(contentType, charset)
|
||||||
|
|
||||||
|
// switch contentType {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// return -1, nil
|
||||||
|
// }
|
||||||
|
|
||||||
// Binary writes out the raw bytes as binary data.
|
// Binary writes out the raw bytes as binary data.
|
||||||
func (ctx *context) Binary(data []byte) (int, error) {
|
func (ctx *context) Binary(data []byte) (int, error) {
|
||||||
ctx.ContentType(ContentBinaryHeaderValue)
|
ctx.ContentType(ContentBinaryHeaderValue)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user