// ServeContent serves content, headers are autoset // receives three parameters, it's low-level function, instead you can use .ServeFile(string) // // You can define your own "Content-Type" header also, after this function call func (ctx *Context) ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error { if t, err := time.Parse(config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) { ctx.RequestCtx.Response.Header.Del(contentType) ctx.RequestCtx.Response.Header.Del(contentLength) ctx.RequestCtx.SetStatusCode(StatusNotModified) return nil } ctx.RequestCtx.Response.Header.Set(contentType, utils.TypeByExtension(filename)) ctx.RequestCtx.Response.Header.Set(lastModified, modtime.UTC().Format(config.TimeFormat)) ctx.RequestCtx.SetStatusCode(StatusOK) var out io.Writer if gzipCompression { ctx.RequestCtx.Response.Header.Add("Content-Encoding", "gzip") gzipWriter := gzipWriterPool.Get().(*gzip.Writer) gzipWriter.Reset(ctx.RequestCtx.Response.BodyWriter()) defer gzipWriter.Close() defer gzipWriterPool.Put(gzipWriter) out = gzipWriter } else { out = ctx.RequestCtx.Response.BodyWriter() } _, err := io.Copy(out, content) return errServeContent.With(err) }
// Favicon serves static favicon // accepts 2 parameters, second is optional // favPath (string), declare the system directory path of the __.ico // requestPath (string), it's the route's path, by default this is the "/favicon.ico" because some browsers tries to get this by default first, // you can declare your own path if you have more than one favicon (desktop, mobile and so on) // // this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself) // Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on) // // panics on error func (api *muxAPI) Favicon(favPath string, requestPath ...string) RouteNameFunc { f, err := os.Open(favPath) if err != nil { panic(errDirectoryFileNotFound.Format(favPath, err.Error())) } defer f.Close() fi, _ := f.Stat() if fi.IsDir() { // if it's dir the try to get the favicon.ico fav := path.Join(favPath, "favicon.ico") f, err = os.Open(fav) if err != nil { //we try again with .png return api.Favicon(path.Join(favPath, "favicon.png")) } favPath = fav fi, _ = f.Stat() } modtime := fi.ModTime().UTC().Format(config.TimeFormat) cType := utils.TypeByExtension(favPath) // copy the bytes here in order to cache and not read the ico on each request. cacheFav := make([]byte, fi.Size()) if _, err = f.Read(cacheFav); err != nil { panic(errDirectoryFileNotFound.Format(favPath, "Couldn't read the data bytes for Favicon: "+err.Error())) } h := func(ctx *Context) { if t, err := time.Parse(config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && fi.ModTime().Before(t.Add(config.StaticCacheDuration)) { ctx.Response.Header.Del(contentType) ctx.Response.Header.Del(contentLength) ctx.SetStatusCode(StatusNotModified) return } ctx.Response.Header.Set(contentType, cType) ctx.Response.Header.Set(lastModified, modtime) ctx.SetStatusCode(StatusOK) ctx.Response.SetBody(cacheFav) } reqPath := "/favicon" + path.Ext(fi.Name()) //we could use the filename, but because standards is /favicon.ico/.png. if len(requestPath) > 0 { reqPath = requestPath[0] } api.Head(reqPath, h) return api.Get(reqPath, h) }