Skip to content

Commit

Permalink
code improvement gzip, loading part
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed Apr 3, 2017
1 parent fa0baf1 commit 47f03ee
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 82 deletions.
12 changes: 1 addition & 11 deletions aah.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ var (
appDefaultHTTPPort = 8080
appDefaultDateFormat = "2006-01-02"
appDefaultDateTimeFormat = "2006-01-02 15:04:05"
appModeWeb = "web"

goPath string
goSrcDir string
Expand Down Expand Up @@ -105,11 +104,6 @@ func AppImportPath() string {
return appImportPath
}

// AppMode method returns aah application mode. Default is "web" For e.g.: web or api
func AppMode() string {
return AppConfig().StringDefault("mode", appModeWeb)
}

// AppHTTPAddress method returns aah application HTTP address otherwise empty string
func AppHTTPAddress() string {
return AppConfig().StringDefault("server.address", "")
Expand Down Expand Up @@ -200,7 +194,6 @@ func Start() {

log.Infof("App Name: %v", AppName())
log.Infof("App Profile: %v", AppProfile())
log.Infof("App Mode: %v", AppMode())
log.Debugf("App i18n Locales: %v", strings.Join(AppI18n().Locales(), ", "))
log.Debugf("App Route Domains: %v", strings.Join(AppRouter().DomainAddresses(), ", "))

Expand Down Expand Up @@ -303,10 +296,7 @@ func initInternal() {
logAsFatal(initLogs(AppConfig()))
logAsFatal(initI18n(appI18nDir()))
logAsFatal(initRoutes(appConfigDir(), AppConfig()))

if AppMode() == appModeWeb {
logAsFatal(initTemplateEngine(appViewsDir(), AppConfig()))
}
logAsFatal(initViewEngine(appViewsDir(), AppConfig()))

if AppProfile() != appProfileProd {
logAsFatal(initTests())
Expand Down
43 changes: 25 additions & 18 deletions engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (
notContinuePipeline
)

const gzipContentEncoding = "gzip"

var errFileNotFound = errors.New("file not found")

type (
Expand Down Expand Up @@ -126,8 +128,6 @@ func (e *engine) prepareContext(w http.ResponseWriter, req *http.Request) *Conte

if ctx.Req.IsGzipAccepted && e.gzipEnabled {
ctx.Res = ahttp.WrapGzipResponseWriter(w, e.gzipLevel)
ctx.Reply().Header(ahttp.HeaderVary, ahttp.HeaderAcceptEncoding)
ctx.Reply().Header(ahttp.HeaderContentEncoding, "gzip")
} else {
ctx.Res = ahttp.WrapResponseWriter(w)
}
Expand Down Expand Up @@ -173,9 +173,17 @@ func (e *engine) handleRoute(ctx *Context) routeStatus {
ctx.route = route
ctx.domain = domain

// Path parameters
if pathParams.Len() > 0 {
ctx.Req.Params.Path = make(map[string]string, pathParams.Len())
for _, v := range *pathParams {
ctx.Req.Params.Path[v.Key] = v.Value
}
}

// Serving static file
if route.IsStatic {
if err := serveStatic(ctx.Res, ctx.Req.Raw, route, pathParams); err == errFileNotFound {
if err := e.serveStatic(ctx); err == errFileNotFound {
handleRouteNotFound(ctx, domain, route)
e.writeReply(ctx)
}
Expand All @@ -189,14 +197,6 @@ func (e *engine) handleRoute(ctx *Context) routeStatus {
return notContinuePipeline
}

// Path parameters
if pathParams.Len() > 0 {
ctx.Req.Params.Path = make(map[string]string, pathParams.Len())
for _, v := range *pathParams {
ctx.Req.Params.Path[v.Key] = v.Value
}
}

return continuePipeline
}

Expand Down Expand Up @@ -264,13 +264,7 @@ func (e *engine) writeReply(ctx *Context) {
}

// Gzip
if ctx.Req.IsGzipAccepted && e.gzipEnabled {
if reply.Code == http.StatusNoContent || buf.Len() == 0 {
ctx.Res.Header().Del(ahttp.HeaderContentEncoding)
}

ctx.Res.Header().Del(ahttp.HeaderContentLength)
}
e.prepareGzipHeaders(ctx, buf.Len() == 0)

// HTTP status
ctx.Res.WriteHeader(reply.Code)
Expand All @@ -282,6 +276,19 @@ func (e *engine) writeReply(ctx *Context) {
publishOnAfterReplyEvent(ctx)
}

// prepareGzipHeaders method prepares appropriate headers for gzip response
func (e *engine) prepareGzipHeaders(ctx *Context, delCntEnc bool) {
if ctx.Req.IsGzipAccepted && e.gzipEnabled {
ctx.Res.Header().Add(ahttp.HeaderVary, ahttp.HeaderAcceptEncoding)
ctx.Res.Header().Add(ahttp.HeaderContentEncoding, gzipContentEncoding)
ctx.Res.Header().Del(ahttp.HeaderContentLength)

if ctx.Reply().Code == http.StatusNoContent || delCntEnc {
ctx.Res.Header().Del(ahttp.HeaderContentEncoding)
}
}
}

// getContext method gets context from pool
func (e *engine) getContext() *Context {
return e.ctxPool.Get().(*Context)
Expand Down
84 changes: 45 additions & 39 deletions static.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,85 +17,91 @@ import (
"aahframework.org/atemplate.v0"
"aahframework.org/essentials.v0"
"aahframework.org/log.v0"
"aahframework.org/router.v0"
)

// serveStatic method static file/directory delivery.
func serveStatic(w http.ResponseWriter, req *http.Request, route *router.Route, pathParams *router.PathParams) error {
func (e *engine) serveStatic(ctx *Context) error {
res, req := ctx.Res, ctx.Req
var fileabs string
if route.IsDir() {
fileabs = filepath.Join(AppBaseDir(), route.Dir, filepath.FromSlash(pathParams.Get("filepath")))
if ctx.route.IsDir() {
fileabs = filepath.Join(AppBaseDir(), ctx.route.Dir, filepath.FromSlash(ctx.Req.Params.PathValue("filepath")))
} else {
fileabs = filepath.Join(AppBaseDir(), "static", filepath.FromSlash(route.File))
fileabs = filepath.Join(AppBaseDir(), "static", filepath.FromSlash(ctx.route.File))
}

dir, file := filepath.Split(fileabs)
log.Tracef("Dir: %s, File: %s", dir, file)

fs := ahttp.Dir(dir, route.ListDir)
fs := ahttp.Dir(dir, ctx.route.ListDir)
f, err := fs.Open(file)
defer ess.CloseQuietly(f)
if err != nil {
if err == ahttp.ErrDirListNotAllowed {
log.Warnf("directory listing not allowed: %s", req.URL.Path)
w.WriteHeader(http.StatusForbidden)
_, _ = w.Write([]byte("403 Directory listing not allowed"))
return nil
log.Warnf("directory listing not allowed: %s", req.Path)
res.WriteHeader(http.StatusForbidden)
fmt.Fprintf(res, "403 Directory listing not allowed")
} else if os.IsNotExist(err) {
log.Errorf("file not found: %s", req.URL.Path)
log.Errorf("file not found: %s", req.Path)
return errFileNotFound
} else if os.IsPermission(err) {
log.Warnf("permission issue: %s", req.URL.Path)
w.WriteHeader(http.StatusForbidden)
_, _ = w.Write([]byte("403 Forbidden"))
return nil
log.Warnf("permission issue: %s", req.Path)
res.WriteHeader(http.StatusForbidden)
fmt.Fprintf(res, "403 Forbidden")
} else {
res.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(res, "500 Internal Server Error")
}

w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("500 Internal Server Error"))
return nil
}
defer ess.CloseQuietly(f)

fi, err := f.Stat()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("500 Internal Server Error"))
res.WriteHeader(http.StatusInternalServerError)
_, _ = res.Write([]byte("500 Internal Server Error"))
return nil
}

if fi.IsDir() {
// redirect if the directory name doesn't end in a slash
if req.URL.Path[len(req.URL.Path)-1] != '/' {
log.Debugf("redirecting to dir: %s", req.URL.Path+"/")
http.Redirect(w, req, path.Base(req.URL.Path)+"/", http.StatusFound)
if req.Path[len(req.Path)-1] != '/' {
log.Debugf("redirecting to dir: %s", req.Path+"/")
http.Redirect(res, req.Raw, path.Base(req.Path)+"/", http.StatusFound)
return nil
}

directoryList(w, req, f)
// Gzip
e.prepareGzipHeaders(ctx, false)

directoryList(res, req.Raw, f)
return nil
}

http.ServeContent(w, req, file, fi.ModTime(), f)
// Gzip
e.prepareGzipHeaders(ctx, false)

http.ServeContent(res, req.Raw, file, fi.ModTime(), f)
return nil
}

func directoryList(w http.ResponseWriter, req *http.Request, f http.File) {
// directoryList method compose directory listing response
func directoryList(res http.ResponseWriter, req *http.Request, f http.File) {
dirs, err := f.Readdir(-1)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("Error reading directory"))
res.WriteHeader(http.StatusInternalServerError)
_, _ = res.Write([]byte("Error reading directory"))
return
}
sort.Sort(byName(dirs))

w.Header().Set(ahttp.HeaderContentType, ahttp.ContentTypeHTML.Raw())
res.Header().Set(ahttp.HeaderContentType, ahttp.ContentTypeHTML.Raw())
reqPath := req.URL.Path
fmt.Fprintf(w, "<html>\n")
fmt.Fprintf(w, "<head><title>Listing of %s</title></head>\n", reqPath)
fmt.Fprintf(w, "<body bgcolor=\"white\">\n")
fmt.Fprintf(w, "<h1>Listing of %s</h1><hr>\n", reqPath)
fmt.Fprintf(w, "<pre><table border=\"0\">\n")
fmt.Fprintf(w, "<tr><td collapse=\"2\"><a href=\"../\">../</a></td></tr>\n")
fmt.Fprintf(res, "<html>\n")
fmt.Fprintf(res, "<head><title>Listing of %s</title></head>\n", reqPath)
fmt.Fprintf(res, "<body bgcolor=\"white\">\n")
fmt.Fprintf(res, "<h1>Listing of %s</h1><hr>\n", reqPath)
fmt.Fprintf(res, "<pre><table border=\"0\">\n")
fmt.Fprintf(res, "<tr><td collapse=\"2\"><a href=\"../\">../</a></td></tr>\n")
for _, d := range dirs {
name := d.Name()
if d.IsDir() {
Expand All @@ -105,15 +111,15 @@ func directoryList(w http.ResponseWriter, req *http.Request, f http.File) {
// part of the URL path, and not indicate the start of a query
// string or fragment.
url := url.URL{Path: name}
fmt.Fprintf(w, "<tr><td><a href=\"%s\">%s</a></td><td width=\"200px\" align=\"right\">%s</td></tr>\n",
fmt.Fprintf(res, "<tr><td><a href=\"%s\">%s</a></td><td width=\"200px\" align=\"right\">%s</td></tr>\n",
url.String(),
atemplate.HTMLEscape(name),
d.ModTime().Format(appDefaultDateTimeFormat),
)
}
fmt.Fprintf(w, "</table></pre>\n")
fmt.Fprintf(w, "<hr></body>\n")
fmt.Fprintf(w, "</html>\n")
fmt.Fprintf(res, "</table></pre>\n")
fmt.Fprintf(res, "<hr></body>\n")
fmt.Fprintf(res, "</html>\n")
}

// Sort interface for Directory list
Expand Down
33 changes: 19 additions & 14 deletions view.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ import (
)

var (
appTemplateEngine atemplate.TemplateEnginer
appViewEngine atemplate.TemplateEnginer
appTemplateExt string
appDefaultTmplLayout string
appTemplateCaseSensitive bool
appViewFileCaseSensitive bool
isExternalTmplEngine bool
)

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Global methods
//___________________________________

// AppTemplateEngine method returns aah application Template Engine instance.
func AppTemplateEngine() atemplate.TemplateEnginer {
return appTemplateEngine
// AppViewEngine method returns aah application view Engine instance.
func AppViewEngine() atemplate.TemplateEnginer {
return appViewEngine
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Expand All @@ -41,28 +41,33 @@ func appViewsDir() string {
return filepath.Join(AppBaseDir(), "views")
}

func initTemplateEngine(viewDir string, appCfg *config.Config) error {
func initViewEngine(viewDir string, appCfg *config.Config) error {
if !ess.IsFileExists(viewDir) {
// view directory not exists
return nil
}

// application config values
appTemplateExt = appCfg.StringDefault("view.ext", ".html")
appDefaultTmplLayout = "master" + appTemplateExt
appTemplateCaseSensitive = appCfg.BoolDefault("view.case_sensitive", false)
appViewFileCaseSensitive = appCfg.BoolDefault("view.case_sensitive", false)

// initialize if external TemplateEngine is not registered.
if appTemplateEngine == nil {
if appViewEngine == nil {
tmplEngineName := appCfg.StringDefault("view.engine", "go")
switch tmplEngineName {
case "go":
appTemplateEngine = &atemplate.TemplateEngine{}
appViewEngine = &atemplate.TemplateEngine{}
}

isExternalTmplEngine = false
} else {
isExternalTmplEngine = true
}

appTemplateEngine.Init(appCfg, viewDir)
appViewEngine.Init(appCfg, viewDir)

return appTemplateEngine.Load()
return appViewEngine.Load()
}

// handlePreReplyStage method does 1) sets response header, 2) if HTML content type
Expand All @@ -82,7 +87,7 @@ func handlePreReplyStage(ctx *Context) {
}

// HTML response
if AppMode() == appModeWeb && ahttp.ContentTypeHTML.IsEqual(reply.ContType) {
if ahttp.ContentTypeHTML.IsEqual(reply.ContType) {
if reply.Rdr == nil {
reply.Rdr = &HTML{}
}
Expand Down Expand Up @@ -147,10 +152,10 @@ func findViewTemplate(ctx *Context) {
}

log.Tracef("Layout: %s, Template Path: %s, Template Name: %s", htmlRdr.Layout, tmplPath, tmplName)
htmlRdr.Template = appTemplateEngine.Get(htmlRdr.Layout, tmplPath, tmplName)
htmlRdr.Template = appViewEngine.Get(htmlRdr.Layout, tmplPath, tmplName)
if htmlRdr.Template == nil {
tmplFile := filepath.Join("views", "pages", controllerName, tmplName)
if !appTemplateCaseSensitive {
if !appViewFileCaseSensitive {
tmplFile = strings.ToLower(tmplFile)
}

Expand Down

0 comments on commit 47f03ee

Please sign in to comment.