Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

148 lines (120 sloc) 3.421 kb
package mango
import (
type Request struct {
type Status int
type Body string
type Headers http.Header
func (h Headers) Add(key, value string) {
textproto.MIMEHeader(h).Add(key, value)
func (h Headers) Set(key, value string) {
textproto.MIMEHeader(h).Set(key, value)
func (h Headers) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
func (h Headers) Del(key string) {
type Env map[string]interface{}
func (this Env) Logger() *log.Logger {
if this["mango.logger"] == nil {
this["mango.logger"] = log.New(os.Stdout, "", log.Ldate|log.Ltime)
return this["mango.logger"].(*log.Logger)
func (this Env) Request() *Request {
return this["mango.request"].(*Request)
func (this Env) Session() map[string]interface{} {
return this["mango.session"].(map[string]interface{})
// This is the core app the user has written
type App func(Env) (Status, Headers, Body)
// These are pieces of middleware,
// which 'wrap' around the core App
// (and each other)
type Middleware func(Env, App) (Status, Headers, Body)
// Bundle a given list of Middleware pieces into a App
func bundle(r ...Middleware) App {
if len(r) <= 1 {
// Terminate the innermost piece of Middleware
// Basically stops it from recursing any further.
return func(input Env) (Status, Headers, Body) {
return r[0](input, func(Env) (Status, Headers, Body) {
panic("Core Mango App should never call it's upstream function.")
return wrap(r[0], bundle(r[1:]...))
// Attach a piece of Middleware to the outside
// of a App. This wraps the inner App
// inside the outer Middleware.
func wrap(middleware Middleware, app App) App {
return func(input Env) (Status, Headers, Body) {
return middleware(input, app)
// Convert a App into Middleware
// We convert the core app into a Middleware
// so we can pass it to Bundle as part of the
// stack. Because the App does not call its
// upstream method, the resulting Middleware
// will just ignore any upstream passed to it.
func middlewareify(app App) Middleware {
return func(input Env, upstream App) (Status, Headers, Body) {
return app(input)
type Stack struct {
Address string
middleware []Middleware
app App
func Version() []int {
return []int{0, 3, 6}
func VersionString() string {
v := Version()
return fmt.Sprintf("%d.%02d.%02d", v[0], v[1], v[2])
func (this *Stack) Middleware(middleware ...Middleware) {
this.middleware = middleware
func (this *Stack) Compile(app App) App { = app
return bundle(append(this.middleware, middlewareify(
func (this *Stack) HandlerFunc(app App) http.HandlerFunc {
compiled_app := this.Compile(app)
return func(w http.ResponseWriter, r *http.Request) {
env := make(map[string]interface{})
env["mango.request"] = &Request{r}
env["mango.version"] = Version()
status, headers, body := compiled_app(env)
for key, values := range headers {
for _, value := range values {
w.Header().Add(key, value)
func (this *Stack) Run(app App) os.Error {
if this.Address == "" {
this.Address = ""
fmt.Println("Starting Mango Stack On:", this.Address)
http.HandleFunc("/", this.HandlerFunc(app))
return http.ListenAndServe(this.Address, nil)
Jump to Line
Something went wrong with that request. Please try again.