diff --git a/HISTORY.md b/HISTORY.md index 053e0a9c..2f8b2319 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -206,6 +206,8 @@ New Context Methods: - `context.IsGRPC() bool` reports whether the request came from a gRPC client - `context.UpsertCookie(*http.Cookie, cookieOptions ...context.CookieOption)` upserts a cookie, fixes [#1485](https://github.com/kataras/iris/issues/1485) too - `context.StopWithStatus(int)` stops the handlers chain and writes the status code +- `context.StopWithText(int, string)` stops the handlers chain, writes thre status code and a plain text message +- `context.StopWithError(int, error)` stops the handlers chain, writes thre status code and the error's message - `context.StopWithJSON(int, interface{})` stops the handlers chain, writes the status code and sends a JSON response - `context.StopWithProblem(int, iris.Problem)` stops the handlers, writes the status code and sends an `application/problem+json` response - `context.Protobuf(proto.Message)` sends protobuf to the client @@ -220,6 +222,8 @@ New Context Methods: Breaking Changes: +Change the MIME type of `Javascript .js` and `JSONP` as the HTML specification now recommends to `"text/javascript"` instead of the obselete `"application/javascript"`. This change was pushed to the `Go` language itself as well. See . + - `var mvc.AutoBinding` removed as the default behavior now resolves such dependencies automatically (see [[FEATURE REQUEST] MVC serving gRPC-compatible controller](https://github.com/kataras/iris/issues/1449)) - `mvc#Application.SortByNumMethods()` removed as the default behavior now binds the "thinnest" empty `interface{}` automatically (see [MVC: service injecting fails](https://github.com/kataras/iris/issues/1343)) - `mvc#BeforeActivation.Dependencies().Add` should be replaced with `mvc#BeforeActivation.Dependencies().Register` instead diff --git a/_examples/file-server/basic/main_test.go b/_examples/file-server/basic/main_test.go index d297c67a..b565fe4e 100644 --- a/_examples/file-server/basic/main_test.go +++ b/_examples/file-server/basic/main_test.go @@ -16,7 +16,7 @@ type resource string func (r resource) contentType() string { switch filepath.Ext(r.String()) { case ".js": - return "application/javascript" + return "text/javascript" case ".css": return "text/css" case ".ico": diff --git a/_examples/file-server/embedding-files-into-app/main_test.go b/_examples/file-server/embedding-files-into-app/main_test.go index 4c1c0531..57a88e8c 100644 --- a/_examples/file-server/embedding-files-into-app/main_test.go +++ b/_examples/file-server/embedding-files-into-app/main_test.go @@ -18,7 +18,7 @@ type resource string func (r resource) contentType() string { switch filepath.Ext(r.String()) { case ".js": - return "application/javascript" + return "text/javascript" case ".css": return "text/css" case ".ico": diff --git a/_examples/file-server/embedding-gziped-files-into-app/main_test.go b/_examples/file-server/embedding-gziped-files-into-app/main_test.go index b774dd63..c8c161be 100644 --- a/_examples/file-server/embedding-gziped-files-into-app/main_test.go +++ b/_examples/file-server/embedding-gziped-files-into-app/main_test.go @@ -20,7 +20,7 @@ type resource string func (r resource) contentType() string { switch filepath.Ext(r.String()) { case ".js": - return "application/javascript" + return "text/javascript" case ".css": return "text/css" case ".ico": diff --git a/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go b/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go index 3d07a4b4..89270787 100644 --- a/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go +++ b/_examples/file-server/single-page-application/embedded-single-page-application/main_test.go @@ -15,7 +15,7 @@ type resource string func (r resource) contentType() string { switch filepath.Ext(r.String()) { case ".js": - return "application/javascript" + return "text/javascript" case ".css": return "text/css" default: diff --git a/_examples/file-server/subdomain/main_test.go b/_examples/file-server/subdomain/main_test.go index d3b8390d..96eb882d 100644 --- a/_examples/file-server/subdomain/main_test.go +++ b/_examples/file-server/subdomain/main_test.go @@ -14,7 +14,7 @@ type resource string func (r resource) contentType() string { switch filepath.Ext(r.String()) { case ".js": - return "application/javascript" + return "text/javascript" case ".css": return "text/css" case ".ico": diff --git a/_examples/http_responsewriter/content-negotiation/main.go b/_examples/http_responsewriter/content-negotiation/main.go index f4971414..d5619e1d 100644 --- a/_examples/http_responsewriter/content-negotiation/main.go +++ b/_examples/http_responsewriter/content-negotiation/main.go @@ -97,7 +97,7 @@ func newApp() *iris.Application { // Markdown: for text/mardown, // Binary: for application/octet-stream, // YAML: for application/x-yaml, - // JSONP: for application/javascript + // JSONP: for text/javascript // Other: for anything else, JSON: jsonAndXML, // for application/json XML: jsonAndXML, // for application/xml or text/xml diff --git a/_examples/http_responsewriter/write-rest/main.go b/_examples/http_responsewriter/write-rest/main.go index 27df7ff9..b861130b 100644 --- a/_examples/http_responsewriter/write-rest/main.go +++ b/_examples/http_responsewriter/write-rest/main.go @@ -49,7 +49,7 @@ func main() { Age: 25, } - // Manually setting a content type: ctx.ContentType("application/javascript") + // Manually setting a content type: ctx.ContentType("text/javascript") ctx.JSON(u) }) diff --git a/context/context.go b/context/context.go index 645f32f8..e3101c5d 100644 --- a/context/context.go +++ b/context/context.go @@ -256,11 +256,23 @@ type Context interface { // IsStopped reports whether the current position of the context's handlers is -1, // means that the StopExecution() was called at least once. IsStopped() bool - // StopWithJSON stops the handlers chain and writes the "statusCode". + // StopWithStatus stops the handlers chain and writes the "statusCode". // // If the status code is a failure one then // it will also fire the specified error code handler. StopWithStatus(statusCode int) + // StopWithText stops the handlers chain and writes the "statusCode" + // among with a message "plainText". + // + // If the status code is a failure one then + // it will also fire the specified error code handler. + StopWithText(statusCode int, plainText string) + // StopWithError stops the handlers chain and writes the "statusCode" + // among with the error "err". + // + // If the status code is a failure one then + // it will also fire the specified error code handler. + StopWithError(statusCode int, err error) // StopWithJSON stops the handlers chain, writes the status code // and sends a JSON response. // @@ -1496,7 +1508,7 @@ func (ctx *context) IsStopped() bool { return ctx.currentHandlerIndex == stopExecutionIndex } -// StopWithJSON stops the handlers chain and writes the "statusCode". +// StopWithStatus stops the handlers chain and writes the "statusCode". // // If the status code is a failure one then // it will also fire the specified error code handler. @@ -1505,6 +1517,30 @@ func (ctx *context) StopWithStatus(statusCode int) { ctx.StatusCode(statusCode) } +// StopWithText stops the handlers chain and writes the "statusCode" +// among with a message "plainText". +// +// If the status code is a failure one then +// it will also fire the specified error code handler. +func (ctx *context) StopWithText(statusCode int, plainText string) { + ctx.WriteString(plainText) + ctx.StopWithStatus(statusCode) +} + +// StopWithError stops the handlers chain and writes the "statusCode" +// among with the error "err". +// +// If the status code is a failure one then +// it will also fire the specified error code handler. +func (ctx *context) StopWithError(statusCode int, err error) { + if err == nil { + return + } + + ctx.WriteString(err.Error()) + ctx.StopWithStatus(statusCode) +} + // StopWithJSON stops the handlers chain, writes the status code // and sends a JSON response. // @@ -3311,7 +3347,7 @@ const ( // Read more at: https://tools.ietf.org/html/rfc7807 ContentXMLProblemHeaderValue = "application/problem+xml" // ContentJavascriptHeaderValue header value for JSONP & Javascript data. - ContentJavascriptHeaderValue = "application/javascript" + ContentJavascriptHeaderValue = "text/javascript" // ContentTextHeaderValue header value for Text data. ContentTextHeaderValue = "text/plain" // ContentXMLHeaderValue header value for XML data. @@ -4160,9 +4196,9 @@ func (n *NegotiationBuilder) Problem(v ...interface{}) *NegotiationBuilder { return n.MIME(ContentJSONProblemHeaderValue+","+ContentXMLProblemHeaderValue, content) } -// JSONP registers the "application/javascript" content type and, optionally, +// JSONP registers the "text/javascript" content type and, optionally, // a value that `Context.Negotiate` will render -// when a client accepts the "application/javascript" content type. +// when a client accepts the "javascript/javascript" content type. // // Returns itself for recursive calls. func (n *NegotiationBuilder) JSONP(v ...interface{}) *NegotiationBuilder { @@ -4446,7 +4482,7 @@ func (n *NegotiationAcceptBuilder) Problem() *NegotiationAcceptBuilder { return n.MIME(ContentJSONProblemHeaderValue, ContentXMLProblemHeaderValue) } -// JSONP adds the "application/javascript" as accepted client content type. +// JSONP adds the "text/javascript" as accepted client content type. // Returns itself. func (n *NegotiationAcceptBuilder) JSONP() *NegotiationAcceptBuilder { return n.MIME(ContentJavascriptHeaderValue) diff --git a/core/router/handler.go b/core/router/handler.go index 28774940..f017968b 100644 --- a/core/router/handler.go +++ b/core/router/handler.go @@ -174,7 +174,7 @@ func (h *routerHandler) Build(provider RoutesProvider) error { defer golog.SetTimeFormat(bckpTimeFormat) golog.SetTimeFormat("") - for _, method := range AllMethods { + for _, method := range AllMethods { // TODO: MethodNone "NONE" with an (offline) status on r.Trace. methodRoutes := collect(method) for _, r := range methodRoutes { golog.Println(r.Trace()) diff --git a/core/router/mime.go b/core/router/mime.go index e24955e1..1fb50b36 100644 --- a/core/router/mime.go +++ b/core/router/mime.go @@ -3,6 +3,8 @@ package router import ( "mime" "path/filepath" + + "github.com/kataras/iris/v12/context" ) var types = map[string]string{ @@ -47,7 +49,7 @@ var types = map[string]string{ ".bsh": "application/x-bsh", ".bz2": "application/x-bzip2", ".bz": "application/x-bzip", - ".c++": "text/plain", + ".c++": context.ContentTextHeaderValue, ".c": "text/x-c", ".cab": "application/vnd.ms-cab-compressed", ".cat": "application/vndms-pkiseccat", @@ -60,8 +62,8 @@ var types = map[string]string{ ".chat": "application/x-chat", ".chrt": "application/vnd.kde.kchart", ".class": "application/java", - ".com": "text/plain", - ".conf": "text/plain", + ".com": context.ContentTextHeaderValue, + ".conf": context.ContentTextHeaderValue, ".cpio": "application/x-cpio", ".cpp": "text/x-c", ".cpt": "application/mac-compactpro", @@ -71,12 +73,12 @@ var types = map[string]string{ ".csh": "text/x-scriptcsh", ".css": "text/css", ".csv": "text/csv", - ".cxx": "text/plain", + ".cxx": context.ContentTextHeaderValue, ".dar": "application/x-dar", ".dcr": "application/x-director", ".deb": "application/x-debian-package", ".deepv": "application/x-deepv", - ".def": "text/plain", + ".def": context.ContentTextHeaderValue, ".der": "application/x-x509-ca-cert", ".dif": "video/x-dv", ".dir": "application/x-director", @@ -118,7 +120,7 @@ var types = map[string]string{ ".frl": "application/freeloader", ".funk": "audio/make", ".g3": "image/g3fax", - ".g": "text/plain", + ".g": context.ContentTextHeaderValue, ".gif": "image/gif", ".gl": "video/gl", ".gsd": "audio/x-gsm", @@ -149,7 +151,7 @@ var types = map[string]string{ ".ico": "image/x-icon", ".ics": "text/calendar", ".icz": "text/calendar", - ".idc": "text/plain", + ".idc": context.ContentTextHeaderValue, ".ief": "image/ief", ".iefs": "image/ief", ".iges": "application/iges", @@ -175,8 +177,9 @@ var types = map[string]string{ ".jpeg": "image/jpeg", ".jpg": "image/jpeg", ".jps": "image/x-jps", - ".js": "application/javascript", - ".json": "application/json", + ".js": context.ContentJavascriptHeaderValue, + ".mjs": context.ContentJavascriptHeaderValue, + ".json": context.ContentJSONHeaderValue, ".jut": "image/jutvision", ".kar": "audio/midi", ".karbon": "application/vnd.kde.karbon", @@ -196,11 +199,11 @@ var types = map[string]string{ ".latex": "application/x-latex", ".lha": "application/lha", ".lhx": "application/octet-stream", - ".list": "text/plain", + ".list": context.ContentTextHeaderValue, ".lma": "audio/nspaudio", - ".log": "text/plain", + ".log": context.ContentTextHeaderValue, ".lsp": "text/x-scriptlisp", - ".lst": "text/plain", + ".lst": context.ContentTextHeaderValue, ".lsx": "text/x-la-asf", ".ltx": "application/x-latex", ".lzh": "application/octet-stream", @@ -213,7 +216,7 @@ var types = map[string]string{ ".man": "application/x-troff-man", ".manifest": "text/cache-manifest", ".map": "application/x-navimap", - ".mar": "text/plain", + ".mar": context.ContentTextHeaderValue, ".mbd": "application/mbedlet", ".mc$": "application/x-magic-cap-package-10", ".mcd": "application/mcad", @@ -366,7 +369,7 @@ var types = map[string]string{ ".saveme": "application/octet-stream", ".sbk": "application/x-tbook", ".scm": "text/x-scriptscheme", - ".sdml": "text/plain", + ".sdml": context.ContentTextHeaderValue, ".sdp": "application/sdp", ".sdr": "application/sounder", ".sea": "application/sea", @@ -415,7 +418,7 @@ var types = map[string]string{ ".tex": "application/x-tex", ".texi": "application/x-texinfo", ".texinfo": "application/x-texinfo", - ".text": "text/plain", + ".text": context.ContentTextHeaderValue, ".tgz": "application/gnutar", ".tif": "image/tiff", ".tiff": "image/tiff", @@ -424,7 +427,7 @@ var types = map[string]string{ ".tsp": "application/dsptype", ".tsv": "text/tab-separated-values", ".turbot": "image/florian", - ".txt": "text/plain", + ".txt": context.ContentTextHeaderValue, ".uil": "text/x-uil", ".uni": "text/uri-list", ".unis": "text/uri-list", @@ -500,7 +503,7 @@ var types = map[string]string{ ".xlv": "application/excel", ".xlw": "application/excel", ".xm": "audio/xm", - ".xml": "text/xml", + ".xml": context.ContentXMLHeaderValue, ".xmz": "xgl/movie", ".xpix": "application/x-vndls-xpix", ".xpm": "image/x-xpixmap", @@ -569,22 +572,21 @@ func TypeByExtension(ext string) (typ string) { } if ext[0] != '.' { // try to take it by filename - typ = TypeByFilename(ext) + typ = context.TrimHeaderValue(TypeByFilename(ext)) if typ == "" { ext = "." + ext // if error or something wrong then prepend the dot } } if typ == "" { - typ = mime.TypeByExtension(ext) + typ = context.TrimHeaderValue(mime.TypeByExtension(ext)) } // mime.TypeByExtension returns as text/plain; | charset=utf-8 the static .js (not always) - if ext == ".js" && (typ == "text/plain" || typ == "text/plain; charset=utf-8") { - if ext == ".js" { - typ = "application/javascript" - } + if ext == ".js" && (typ == context.ContentJavascriptHeaderValue || typ == context.ContentTextHeaderValue) { + typ = context.ContentJavascriptHeaderValue } + return typ }