Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.5.1 Release #45

Merged
merged 3 commits into from
May 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# aah web framework for Go
[![Build Status](https://travis-ci.org/go-aah/aah.svg?branch=master)](https://travis-ci.org/go-aah/aah) [![codecov](https://codecov.io/gh/go-aah/aah/branch/master/graph/badge.svg)](https://codecov.io/gh/go-aah/aah/branch/master) [![Go Report Card](https://goreportcard.com/badge/aahframework.org/aah.v0)](https://goreportcard.com/report/aahframework.org/aah.v0)
[![Powered by Go](https://img.shields.io/badge/powered_by-go-blue.svg)](https://golang.org)
[![Version](https://img.shields.io/badge/version-0.5-blue.svg)](https://github.com/go-aah/aah/releases/latest) [![GoDoc](https://godoc.org/aahframework.org/aah.v0?status.svg)](https://godoc.org/aahframework.org/aah.v0)
[![Version](https://img.shields.io/badge/version-0.5.1-blue.svg)](https://github.com/go-aah/aah/releases/latest) [![GoDoc](https://godoc.org/aahframework.org/aah.v0?status.svg)](https://godoc.org/aahframework.org/aah.v0)
[![License](https://img.shields.io/github/license/go-aah/aah.svg)](LICENSE)

***Release [v0.5](https://github.com/go-aah/aah/releases/latest) tagged on May 19, 2017***
***Release [v0.5.1](https://github.com/go-aah/aah/releases/latest) tagged on May 21, 2017***

aah framework - A scalable, performant, rapid development Web framework for Go.

Expand Down
2 changes: 1 addition & 1 deletion aah.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
)

// Version no. of aah framework
const Version = "0.5"
const Version = "0.5.1"

// aah application variables
var (
Expand Down
2 changes: 1 addition & 1 deletion aah_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func TestAahRecover(t *testing.T) {
}

func TestAahLogDir(t *testing.T) {
logsDir := filepath.Join(getTestdataPath(), "logs")
logsDir := filepath.Join(getTestdataPath(), appLogsDir())
logFile := filepath.Join(logsDir, "test.log")
defer ess.DeleteFiles(logsDir)

Expand Down
14 changes: 7 additions & 7 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,12 @@ func TestContextNil(t *testing.T) {
func TestContextEmbeddedAndController(t *testing.T) {
addToCRegistry()

assertEmbeddedIndexes(t, Level1{}, [][]int{{0}})
assertEmbeddedIndexes(t, Level2{}, [][]int{{0, 0}})
assertEmbeddedIndexes(t, Level3{}, [][]int{{0, 0, 0}})
assertEmbeddedIndexes(t, Level4{}, [][]int{{0, 0, 0, 0}})
assertEmbeddedIndexes(t, Path1{}, [][]int{{1}})
assertEmbeddedIndexes(t, Path2{}, [][]int{{0, 0}, {1, 1}, {2, 0, 0, 0, 0}})
testEmbeddedIndexes(t, Level1{}, [][]int{{0}})
testEmbeddedIndexes(t, Level2{}, [][]int{{0, 0}})
testEmbeddedIndexes(t, Level3{}, [][]int{{0, 0, 0}})
testEmbeddedIndexes(t, Level4{}, [][]int{{0, 0, 0, 0}})
testEmbeddedIndexes(t, Path1{}, [][]int{{1}})
testEmbeddedIndexes(t, Path2{}, [][]int{{0, 0}, {1, 1}, {2, 0, 0, 0, 0}})
}

func TestContextSetURL(t *testing.T) {
Expand Down Expand Up @@ -234,7 +234,7 @@ func TestContextSetMethod(t *testing.T) {
assert.Equal(t, "GET", ctx.Req.Method)
}

func assertEmbeddedIndexes(t *testing.T, c interface{}, expected [][]int) {
func testEmbeddedIndexes(t *testing.T, c interface{}, expected [][]int) {
actual := findEmbeddedContext(reflect.TypeOf(c))
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Indexes do not match. expected %v actual %v", expected, actual)
Expand Down
4 changes: 1 addition & 3 deletions param_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"testing"

"aahframework.org/ahttp.v0"
ess "aahframework.org/essentials.v0"
"aahframework.org/essentials.v0"
"aahframework.org/test.v0/assert"
)

Expand Down Expand Up @@ -46,8 +46,6 @@ func TestParamTemplateFuncs(t *testing.T) {

func TestParamParse(t *testing.T) {
defer ess.DeleteFiles("testapp.pid")
testEng.Lock()
defer testEng.Unlock()

r1 := httptest.NewRequest("GET", "http://localhost:8080/index.html?lang=en-CA", nil)
ctx1 := &Context{
Expand Down
6 changes: 2 additions & 4 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ func TestServerStart1(t *testing.T) {

func TestServerStart2(t *testing.T) {
defer ess.DeleteFiles("testapp.pid")
testEng.Lock()
defer testEng.Unlock()

// App Config
cfgDir := filepath.Join(getTestdataPath(), appConfigDir())
Expand Down Expand Up @@ -67,6 +65,6 @@ func TestServerStart2(t *testing.T) {
Date: buildTime,
Version: "1.0.0",
})
AppConfig().SetString("server.port", "8080")
go Start()
AppConfig().SetString("server.port", "80")
Start()
}
69 changes: 40 additions & 29 deletions static.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,23 @@ import (
"aahframework.org/log.v0"
)

const dirStatic = "static"

// serveStatic method static file/directory delivery.
func (e *engine) serveStatic(ctx *Context) error {
// TODO static assets Dynamic minify for JS and CSS for non-dev profile
dir, file := filepath.Split(getFilepath(ctx))
log.Tracef("Dir: %s, File: %s", dir, file)

ctx.Reply().gzip = checkGzipRequired(file)
e.wrapGzipWriter(ctx)
e.writeHeaders(ctx)
// Determine route is file or directory as per user defined
// static route config (refer to https://docs.aahframework.org/static-files.html#section-static).
// httpDir -> value is from routes config
// filePath -> value is from request
httpDir, filePath := getHTTPDirAndFilePath(ctx)
log.Tracef("Dir: %s, Filepath: %s", httpDir, filePath)

res, req := ctx.Res, ctx.Req
fs := ahttp.Dir(dir, ctx.route.ListDir)
f, err := fs.Open(file)
f, err := httpDir.Open(filePath)
if err != nil {
if err == ahttp.ErrDirListNotAllowed {
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) {
if os.IsNotExist(err) {
log.Errorf("file not found: %s", req.Path)
return errFileNotFound
} else if os.IsPermission(err) {
Expand All @@ -48,20 +46,36 @@ func (e *engine) serveStatic(ctx *Context) error {
res.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(res, "500 Internal Server Error")
}

return nil
}

defer ess.CloseQuietly(f)

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

if fi.IsDir() {
// Gzip
ctx.Reply().gzip = checkGzipRequired(filePath)
e.wrapGzipWriter(ctx)
e.writeHeaders(ctx)

// Serve file
if fi.Mode().IsRegular() {
// 'OnPreReply' server extension point
publishOnPreReplyEvent(ctx)

http.ServeContent(ctx.Res, ctx.Req.Raw, path.Base(filePath), fi.ModTime(), f)

// 'OnAfterReply' server extension point
publishOnAfterReplyEvent(ctx)
return nil
}

// Serve directory
if fi.Mode().IsDir() && ctx.route.ListDir {
// redirect if the directory name doesn't end in a slash
if req.Path[len(req.Path)-1] != '/' {
log.Debugf("redirecting to dir: %s", req.Path+"/")
Expand All @@ -79,13 +93,11 @@ func (e *engine) serveStatic(ctx *Context) error {
return nil
}

// 'OnPreReply' server extension point
publishOnPreReplyEvent(ctx)

http.ServeContent(res, req.Raw, file, fi.ModTime(), f)
// Flow reached here it means directory listing is not allowed
log.Warnf("directory listing not allowed: %s", req.Path)
res.WriteHeader(http.StatusForbidden)
fmt.Fprintf(res, "403 Directory listing not allowed")

// 'OnAfterReply' server extension point
publishOnAfterReplyEvent(ctx)
return nil
}

Expand Down Expand Up @@ -138,14 +150,13 @@ func checkGzipRequired(file string) bool {
}
}

func getFilepath(ctx *Context) string {
var file string
if ctx.route.IsDir() {
file = filepath.Join(AppBaseDir(), ctx.route.Dir, ctx.Req.PathValue("filepath"))
} else {
file = filepath.Join(AppBaseDir(), "static", ctx.route.File)
// getHTTPDirAndFilePath method returns the `http.Dir` and requested file path.
// Note: `ctx.route.*` values come from application routes configuration.
func getHTTPDirAndFilePath(ctx *Context) (http.Dir, string) {
if ctx.route.IsFile() { // this is configured value from routes.conf
return http.Dir(filepath.Join(AppBaseDir(), dirStatic)), ctx.route.File
}
return filepath.FromSlash(file)
return http.Dir(filepath.Join(AppBaseDir(), ctx.route.Dir)), ctx.Req.PathValue("filepath")
}

// Sort interface for Directory list
Expand Down
67 changes: 67 additions & 0 deletions static_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
// go-aah/aah source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package aah

import (
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"

"aahframework.org/config.v0"
"aahframework.org/router.v0"
"aahframework.org/test.v0/assert"
)

func TestStaticDirectoryListing(t *testing.T) {
appCfg, _ := config.ParseString("")
e := newEngine(appCfg)

testStaticServe(t, e, "http://localhost:8080/static/css/aah\x00.css", "static", "css/aah\x00.css", "", "500 Internal Server Error", false)

testStaticServe(t, e, "http://localhost:8080/static/test.txt", "static", "test.txt", "", "This is file content of test.txt", false)

testStaticServe(t, e, "http://localhost:8080/static", "static", "", "", "403 Directory listing not allowed", false)

testStaticServe(t, e, "http://localhost:8080/static", "static", "", "", `<a href="/static/">Found</a>`, true)

testStaticServe(t, e, "http://localhost:8080/static/", "static", "", "", `<title>Listing of /static/</title>`, true)

testStaticServe(t, e, "http://localhost:8080/robots.txt", "", "", "test.txt", "This is file content of test.txt", false)
}

func TestStaticMisc(t *testing.T) {
// File extension check for gzip
v1 := checkGzipRequired("sample.css")
assert.True(t, v1)

v2 := checkGzipRequired("font.otf")
assert.True(t, v2)

// directoryList for read error
r1 := httptest.NewRequest("GET", "http://localhost:8080/assets/css/app.css", nil)
w1 := httptest.NewRecorder()
f, err := os.Open(filepath.Join(getTestdataPath(), "static", "test.txt"))
assert.Nil(t, err)

directoryList(w1, r1, f)
assert.Equal(t, "Error reading directory", w1.Body.String())
}

func testStaticServe(t *testing.T, e *engine, reqURL, dir, filePath, file, result string, listDir bool) {
r := httptest.NewRequest("GET", reqURL, nil)
w := httptest.NewRecorder()
ctx := e.prepareContext(w, r)
ctx.route = &router.Route{IsStatic: true, Dir: dir, ListDir: listDir, File: file}
ctx.Req.Params.Path = map[string]string{
"filepath": filePath,
}
appBaseDir = getTestdataPath()
err := e.serveStatic(ctx)
appBaseDir = ""
assert.Nil(t, err)
assert.True(t, strings.Contains(w.Body.String(), result))
}
2 changes: 1 addition & 1 deletion testdata/static/test.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test.txt
This is file content of test.txt
7 changes: 1 addition & 6 deletions view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"net/http/httptest"
"path/filepath"
"strings"
"sync"
"testing"

"aahframework.org/ahttp.v0"
Expand Down Expand Up @@ -96,12 +95,8 @@ func TestViewStore(t *testing.T) {
assert.False(t, found)
}

var testEng = sync.Mutex{}

func TestViewResolveView(t *testing.T) {
defer ess.DeleteFiles("testapp.pid")
testEng.Lock()
defer testEng.Unlock()
appCfg, _ := config.ParseString("")
e := newEngine(appCfg)

Expand Down Expand Up @@ -131,7 +126,7 @@ func TestViewResolveView(t *testing.T) {
assert.Equal(t, "http", htmlRdr.ViewArgs["Scheme"])
assert.Equal(t, "localhost:8080", htmlRdr.ViewArgs["Host"])
assert.Equal(t, "/index.html", htmlRdr.ViewArgs["RequestPath"])
assert.Equal(t, "0.5", htmlRdr.ViewArgs["AahVersion"])
assert.Equal(t, Version, htmlRdr.ViewArgs["AahVersion"])
assert.Equal(t, "aah framework", htmlRdr.ViewArgs["MyName"])

// cleanup
Expand Down