Пример #1
0
func TestWrapPanic(t *testing.T) {
	var buf bytes.Buffer
	reqlog.SetLogger(stdlog.New(&buf, "", 0))

	mux := goji.NewMux()

	mux.HandleFunc(pat.New("/safe"), func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
	})
	mux.HandleFunc(pat.New("/panic"), func(w http.ResponseWriter, r *http.Request) {
		panic("hi there!")
	})

	mux.UseC(respond.WrapPanicC)

	req, err := http.NewRequest("FOO", "/safe", nil)
	if err != nil {
		t.Fatal(err)
	}

	rr := httptest.NewRecorder()
	mux.ServeHTTP(rr, req)

	if err := apptest.AssertStatus(rr, http.StatusNoContent); err != nil {
		t.Error(err)
	}

	buf.Reset()
	rr = httptest.NewRecorder()
	req.URL.Path = "/panic"
	mux.ServeHTTP(rr, req)

	if err := apptest.AssertStatus(rr, http.StatusInternalServerError); err != nil {
		t.Error(err)
	}

	t.Log(rr.Body.String())
	uerr, err := usererrors.UnmarshalJSON(rr.Body.Bytes())
	if err != nil {
		t.Fatal(err)
	}

	_, ok := uerr.(usererrors.InternalFailure)
	if !ok {
		t.Errorf("expected an InternalFailure but got %#v", uerr)
	}

	t.Log(buf.String())
}
Пример #2
0
// Add implements mux support for a given resource which is effectively handled as:
// pat.New("/(prefix/)resource.Plu*)
func (a *API) Add(resource *Resource) {

	// track our associated resources, will enable auto-generation docs later
	a.Resources[resource.Type] = resource

	// Because of how prefix matches work:
	// https://godoc.org/github.com/goji/goji/pat#hdr-Prefix_Matches
	// We need two separate routes,
	// /(prefix/)resources
	matcher := path.Join(a.prefix, resource.Type)
	a.Mux.HandleC(pat.New(matcher), resource)

	// And:
	// /(prefix/)resources/*
	idMatcher := path.Join(a.prefix, resource.Type, "*")
	a.Mux.HandleC(pat.New(idMatcher), resource)
}
Пример #3
0
func New(cfg *config.Config, r brew.Reader) http.Handler {
	mux := goji.NewMux()

	app := Web{
		r: r,
		t: template.Must(template.New("card").Parse(tmpl)),
	}

	// Setup middleware
	mux.UseC(api.Recover)
	mux.UseC(api.Tracing)

	mux.HandleFuncC(pat.Get("/mtg/cards/:id"), app.HandleCard)
	mux.Handle(pat.New("/*"), http.FileServer(http.Dir("./web/static/")))

	return mux
}
Пример #4
0
func API() *goji.Mux {
	mux := goji.SubMux()

	// We pass the routes as relative to the point where the API router
	// will be mounted.  The super-router will strip any prefix off for us.
	mux.HandleFuncC(pat.Get("/people"), api.ListPeople)
	mux.HandleFuncC(pat.Post("/people"), api.CreatePerson)
	mux.HandleFuncC(pat.Get("/people/:person"), api.GetPerson)
	mux.HandleFuncC(pat.Delete("/people/:person"), api.DeletePerson)

	// Add default 'not found' route that responds with JSON
	mux.HandleFunc(pat.New("/*"), func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(404)
		fmt.Fprint(w, `{"error":"not found"}`)
	})

	return mux
}
Пример #5
0
func TestMetrics(t *testing.T) {
	backend := &stubBackend{}
	metrics.SetBackend(backend)

	inner := goji.NewMux()
	inner.HandleFunc(pat.Get("/:baz"), func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(1)
	})
	inner.UseC(metrics.WrapSubmuxC)

	outer := goji.NewMux()
	outer.HandleFunc(pat.Get("/foo"), func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(2)
	})
	outer.HandleC(pat.New("/bar/*"), inner)
	outer.UseC(metrics.WrapC)

	cases := []struct {
		path   string
		expect map[string]int
	}{
		{"/foo", map[string]int{"foo.request": 1, "foo.response.2": 1}},
		{"/bar/baz", map[string]int{"bar.:baz.request": 1, "bar.:baz.response.1": 1}},
		{"/bar", map[string]int{}},
	}

	for _, testcase := range cases {
		backend.Reset()
		req, err := http.NewRequest("GET", testcase.path, nil)
		if err != nil {
			t.Fatal(err)
		}

		rr := httptest.NewRecorder()
		outer.ServeHTTPC(context.Background(), rr, req)

		if have, want := backend.data, testcase.expect; !reflect.DeepEqual(have, want) {
			t.Errorf("%s: Expected %#v but got %#v", testcase.path, want, have)
		}
	}
}
Пример #6
0
// New creates an App for the given configuration.
func New(config *Configuration) (*App, error) {
	var app App

	db, err := buildDB(config.DBDSN, config.DBMaxIdle, config.DBMaxOpen)
	if err != nil {
		defer app.Close()
		return nil, err
	}
	app.closers = append(app.closers, db)

	ipQuota := throttled.RateQuota{throttled.PerMin(config.IPPerMinute), config.IPRateBurst}
	ipLimiter, err := buildLimiter(ipQuota)

	authCtrl, err := auth.New(config.UserSecret)
	if err != nil {
		defer app.Close()
		return nil, err
	}

	sayCtrl, err := say.New(db)
	if err != nil {
		defer app.Close()
		return nil, err
	}
	app.closers = append(app.closers, sayCtrl)

	// TODO: Proper not found handler
	privMux := goji.NewMux()
	privMux.UseC(metrics.WrapSubmuxC)
	privMux.UseC(authCtrl.WrapC)

	privMux.HandleFuncC(Routes.GetAnimals, sayCtrl.GetAnimals)

	privMux.HandleFuncC(Routes.ListMoods, sayCtrl.ListMoods)
	privMux.HandleFuncC(Routes.SetMood, sayCtrl.SetMood)
	privMux.HandleFuncC(Routes.GetMood, sayCtrl.GetMood)
	privMux.HandleFuncC(Routes.DeleteMood, sayCtrl.DeleteMood)

	privMux.HandleFuncC(Routes.ListConversations, sayCtrl.ListConversations)
	privMux.HandleFuncC(Routes.CreateConversation, sayCtrl.CreateConversation)
	privMux.HandleFuncC(Routes.GetConversation, sayCtrl.GetConversation)
	privMux.HandleFuncC(Routes.DeleteConversation, sayCtrl.DeleteConversation)

	privMux.HandleFuncC(Routes.CreateLine, sayCtrl.CreateLine)
	privMux.HandleFuncC(Routes.GetLine, sayCtrl.GetLine)
	privMux.HandleFuncC(Routes.DeleteLine, sayCtrl.DeleteLine)

	mainMux := goji.NewMux()
	mainMux.HandleFuncC(Routes.CreateUser, authCtrl.CreateUser)
	mainMux.HandleFuncC(Routes.GetUser, authCtrl.GetUser)
	mainMux.HandleC(pat.New("/*"), privMux)

	mainMux.UseC(reqlog.WrapC)
	mainMux.UseC(respond.WrapPanicC)
	mainMux.UseC(metrics.WrapC)
	mainMux.Use(ipLimiter.RateLimit)

	app.srv = mainMux

	return &app, nil
}
Пример #7
0
func main() {
	log.Printf("initializing project_name=%q version=%q revision=%q",
		conf.ProjectName,
		conf.Version,
		conf.Revision)

	// Connect to the database.
	db, err := database.Connect(conf.C.DbType, conf.C.DbConn)
	if err != nil {
		log.Printf("could not connect to database err=%q db_type=%q db_conn=%q",
			err,
			conf.C.DbType,
			conf.C.DbConn)
		return
	}

	// Create datastore.
	ds := database.NewDatastore(db)

	// Create API router and add middleware.
	apiMux := router.API()
	apiMux.Use(middleware.Options)
	apiMux.Use(middleware.JSON)

	// Create web router.
	webMux := router.Web()

	// Create root mux and add common middleware.
	rootMux := goji.NewMux()
	rootMux.UseC(middleware.RequestID)
	rootMux.UseC(middleware.Logger)
	rootMux.UseC(middleware.Recoverer)
	rootMux.Use(middleware.SetHeaders)

	// Serve all static assets from the root.
	serveAssetAt := func(asset, path string) {
		info, _ := static.AssetInfo(asset)
		modTime := info.ModTime()
		data := static.MustAsset(asset)

		webMux.Handle(pat.Get(path), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			log.Printf("debug: serving asset: %s", asset)
			http.ServeContent(w, r, asset, modTime, bytes.NewReader(data))
		}))
	}
	for _, asset := range static.AssetNames() {
		log.Printf("debug: adding route for asset: %s", asset)
		serveAssetAt(asset, "/static/"+asset)
	}

	// Special case a bunch of assets that should be served from the root.
	for _, asset := range []string{
		"clientaccesspolicy.xml",
		"crossdomain.xml",
		"favicon.ico",
		"humans.txt",
		"robots.txt",
	} {
		// Note: only serve if we have this asset.
		if _, err := static.Asset(asset); err == nil {
			log.Printf("debug: adding special route for asset: %s", asset)
			serveAssetAt(asset, "/"+asset)
		}
	}

	// Serve the index page if we have one.
	for _, asset := range []string{"index.html", "index.htm"} {
		// Note: only serve if we have this asset, and only serve the first
		// option.
		if _, err := static.Asset(asset); err == nil {
			log.Printf("debug: adding index route for asset: %s", asset)
			serveAssetAt(asset, "/")
			break
		}
	}

	// Mount the API/Web muxes last (since order matters).
	rootMux.HandleC(pat.New("/api/*"), apiMux)
	rootMux.HandleC(pat.New("/*"), webMux)

	// Create a top-level wrapper that implements ServeHTTP, so we can inject
	// the root (Background) context and any other contexts that we wish to
	// inject.
	outer := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := context.Background()
		ctx = datastore.NewContext(ctx, ds)
		rootMux.ServeHTTPC(ctx, w, r)
	})

	// Start serving
	log.Printf("starting server on: %s", conf.C.HostString())
	graceful.Run(conf.C.HostString(), 10*time.Second, outer)
	log.Printf("server finished")
}
Пример #8
0
func (m *Mux) Handle(pattern string, submux *Mux) {
	handleMap(m, submux, pattern)
	m.webmux.Handle(pat.New(pattern), submux.Mux())
}