Example #1
0
func dbmMiddleware(ctx context.Context) web.MiddlewareType {
	return func(c *web.C, h http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			gtx.Set(c, ctx)
			h.ServeHTTP(w, r)
		}
		return http.HandlerFunc(fn)
	}
}
Example #2
0
// contextMiddleware creates a new go.net/context and
// injects into the current goji context.
func contextMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var ctx = context.Background()
		ctx = datasql.NewContext(ctx, db)
		ctx = blobsql.NewContext(ctx, db)
		ctx = pool.NewContext(ctx, workers)
		ctx = director.NewContext(ctx, worker)

		// add the context to the goji web context
		webcontext.Set(c, ctx)
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
func contextMiddleware(parent context.Context) func(c *web.C, next http.Handler) http.Handler {
	return func(c *web.C, next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			ctx := parent
			ctx = requestid.ContextFromC(ctx, c)
			ctx, cancel := httpx.RequestContext(ctx, w, r)

			gctx.Set(c, ctx)
			defer cancel()
			next.ServeHTTP(w, r)
		}
		return http.HandlerFunc(fn)
	}
}
Example #4
0
// ContextMiddleware creates a new go.net/context and
// injects into the current goji context.
func ContextMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var ctx = context.Background()
		ctx = datastore.NewContext(ctx, database.NewDatastore(db))
		ctx = blobstore.NewContext(ctx, database.NewBlobstore(db))
		ctx = pool.NewContext(ctx, workers)
		ctx = director.NewContext(ctx, worker)
		ctx = pubsub.NewContext(ctx, pub)
		ctx = capability.NewContext(ctx, caps)

		// add the context to the goji web context
		webcontext.Set(c, ctx)
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
Example #5
0
func contextMiddleware(parent context.Context) func(c *web.C, next http.Handler) http.Handler {
	return func(c *web.C, next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			ctx := parent
			ctx = requestid.ContextFromC(ctx, c)

			// establish "cancel on close" context if possible
			if _, ok := w.(http.CloseNotifier); ok {
				ctx = httpx.CancelWhenClosed(ctx, w)
			}

			gctx.Set(c, ctx)
			next.ServeHTTP(w, r)
		}
		return http.HandlerFunc(fn)
	}
}
Example #6
0
// ContextMiddleware will add our variables to the per-request context.
func ContextMiddleware(vars *Vars) web.MiddlewareType {
	mfn := func(c *web.C, h http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			ctx := context.Background()
			ctx = datastore.NewContext(ctx, vars.ds)
			ctx = log.NewContext(ctx, vars.log)

			// Add the context to the goji web context
			webcontext.Set(c, ctx)
			h.ServeHTTP(w, r)
		}

		return http.HandlerFunc(fn)
	}

	return mfn
}
Example #7
0
// LoggerMiddleware is the middleware that logs http requests and resposnes
// to the logging subsytem of horizon.
func LoggerMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		ctx := gctx.FromC(*c)
		mw := mutil.WrapWriter(w)

		logger := log.WithField("req", middleware.GetReqID(*c))

		ctx = log.Set(ctx, logger)
		gctx.Set(c, ctx)

		logStartOfRequest(ctx, r)

		then := time.Now()
		h.ServeHTTP(mw, r)
		duration := time.Now().Sub(then)

		logEndOfRequest(ctx, duration, mw)
	}

	return http.HandlerFunc(fn)
}
Example #8
0
func TestExtDirect(t *testing.T) {
	SetLogger(&LogrusLogger{nblogger.Create()})
	logrus.SetLevel(logrus.DebugLevel)

	Convey("Default provider serialization", t, func() {
		value, err := Provider.JSON()
		So(err, ShouldBeNil)
		So(value, ShouldEqual, "{\"type\":\"remoting\",\"url\":\"/directapi\",\"namespace\":\"DirectApi\",\"timeout\":30000,\"actions\":{}}")
	})

	Convey("Action registration", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))

		Convey("One registered action with name 'Db' expected", func() {
			So(len(provider.Actions), ShouldEqual, 1)
			So(provider.Actions, ShouldContainKey, "Db")
			Convey("and has 9 methods", func() {
				So(len(provider.Actions["Db"]), ShouldEqual, 10)
				Convey("test", func() {
					method, exists, err := From(provider.Actions["Db"]).FirstBy(func(x T) (bool, error) {
						if m, ok := x.(directMethod); ok {
							return m.Name == "test", nil
						} else {
							return false, nil
						}
					})
					So(err, ShouldBeNil)
					So(exists, ShouldBeTrue)
					So(method.(directMethod).Name, ShouldEqual, "test")
					Convey("with no arguments", func() {
						So(*method.(directMethod).Len, ShouldBeZeroValue)
					})
				})
				Convey("getRecords", func() {
					method, exists, err := From(provider.Actions["Db"]).FirstBy(func(x T) (bool, error) {
						if m, ok := x.(directMethod); ok {
							return m.Name == "getRecords", nil
						} else {
							return false, nil
						}
					})
					So(err, ShouldBeNil)
					So(exists, ShouldBeTrue)
					So(method.(directMethod).Name, ShouldEqual, "getRecords")
					Convey("with 1 argument", func() {
						So(*method.(directMethod).Len, ShouldEqual, 1)
					})
				})
				Convey("testEcho1", func() {
					method, exists, err := From(provider.Actions["Db"]).FirstBy(func(x T) (bool, error) {
						if m, ok := x.(directMethod); ok {
							return m.Name == "testEcho1", nil
						} else {
							return false, nil
						}
					})
					So(err, ShouldBeNil)
					So(exists, ShouldBeTrue)
					So(method.(directMethod).Name, ShouldEqual, "testEcho1")
					Convey("with 1 argument", func() {
						So(*method.(directMethod).Len, ShouldEqual, 1)
					})
				})
				Convey("testEcho2", func() {
					method, exists, err := From(provider.Actions["Db"]).FirstBy(func(x T) (bool, error) {
						if m, ok := x.(directMethod); ok {
							return m.Name == "testEcho2", nil
						} else {
							return false, nil
						}
					})
					So(err, ShouldBeNil)
					So(exists, ShouldBeTrue)
					So(method.(directMethod).Name, ShouldEqual, "testEcho2")
					Convey("with 7 arguments", func() {
						So(*method.(directMethod).Len, ShouldEqual, 7)
					})
				})
				Convey("updateBasicInfo", func() {
					method, exists, err := From(provider.Actions["Db"]).FirstBy(func(x T) (bool, error) {
						if m, ok := x.(directMethod); ok {
							return m.Name == "updateBasicInfo", nil
						} else {
							return false, nil
						}
					})
					So(err, ShouldBeNil)
					So(exists, ShouldBeTrue)
					So(method.(directMethod).Name, ShouldEqual, "updateBasicInfo")
					Convey("marked as form handler", func() {
						So(method.(directMethod).FormHandler, ShouldNotBeNil)
						So(*method.(directMethod).FormHandler, ShouldBeTrue)
					})
					Convey("has no len property", func() {
						So(method.(directMethod).Len, ShouldBeNil)
					})
				})
			})
		})

		Convey("Action with methods serialization", func() {
			jsonText, err := provider.JSON()
			So(err, ShouldBeNil)
			So(jsonText, ShouldEqual, `{"type":"remoting","url":"/directapi","namespace":"DirectApi","timeout":30000,"actions":{"Db":[{"name":"getRecords","len":1},{"name":"test","len":0},{"name":"testEcho1","len":1},{"name":"testEcho2","len":7},{"name":"testException1","len":0},{"name":"testException2","len":0},{"name":"testException3","len":0},{"name":"testException4","len":0},{"name":"testTime","len":1},{"name":"updateBasicInfo","formHander":true}]}}`)
			javaScript, err2 := provider.JavaScript()
			So(err2, ShouldBeNil)
			So(javaScript, ShouldEqual, `Ext.ns("DirectApi");DirectApi.REMOTE_API={"type":"remoting","url":"/directapi","namespace":"DirectApi","timeout":30000,"actions":{"Db":[{"name":"getRecords","len":1},{"name":"test","len":0},{"name":"testEcho1","len":1},{"name":"testEcho2","len":7},{"name":"testException1","len":0},{"name":"testException2","len":0},{"name":"testException3","len":0},{"name":"testException4","len":0},{"name":"testTime","len":1},{"name":"updateBasicInfo","formHander":true}]}}`)
		})

		Convey("Duplicated registration", func() {
			provider.RegisterAction(reflect.TypeOf(Db{}))
			So(len(provider.Actions), ShouldEqual, 1)
		})
	})

	Convey("Request with single action call", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))
		reqs := mustDecodeTransaction(strings.NewReader(`{"action":"Db","method":"test","data":null,"type":"rpc","tid":1}`))
		Convey("has one parsed request with correct fields", func() {
			So(len(reqs), ShouldEqual, 1)
			So(reqs[0].Action, ShouldEqual, "Db")
			So(reqs[0].Method, ShouldEqual, "test")
			So(string(reqs[0].Data), ShouldEqual, "null")
			So(reqs[0].Tid, ShouldEqual, 1)
			So(reqs[0].Type, ShouldEqual, "rpc")
			Convey("which is processed into 1 response with correct fields", func() {
				var resps = provider.processRequests(nil, nil, reqs)
				So(len(resps), ShouldEqual, 1)
				So(resps[0].Action, ShouldEqual, "Db")
				So(resps[0].Method, ShouldEqual, "test")
				So(resps[0].Result, ShouldBeEmpty)
				So(resps[0].Tid, ShouldEqual, 1)
				So(resps[0].Type, ShouldEqual, "rpc")
				So(resps[0].Message, ShouldBeNil)
				Convey("which is serialized correctly", func() {
					s, err := json.Marshal(resps)
					So(err, ShouldBeNil)
					// Response is always array even for single request
					So(string(s), ShouldEqual, `[{"type":"rpc","tid":1,"action":"Db","method":"test","result":""}]`)
				})
			})
		})
	})

	Convey("Request with multiple actions call", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))
		reqs := mustDecodeTransaction(strings.NewReader(`[{"action":"Db","method":"testEcho1","data":["Hello!"],"type":"rpc","tid":1},{"action":"Db","method":"testEcho2","data":["Hello", 1, 2, 3, 4, null, null],"type":"rpc","tid":2}]`))
		Convey("has 2 parsed requests with correct fields", func() {
			So(len(reqs), ShouldEqual, 2)
			So(reqs[0].Action, ShouldEqual, "Db")
			So(reqs[0].Method, ShouldEqual, "testEcho1")
			So(string(reqs[0].Data), ShouldEqual, `["Hello!"]`)
			So(reqs[0].Tid, ShouldEqual, 1)
			So(reqs[0].Type, ShouldEqual, "rpc")

			So(reqs[1].Action, ShouldEqual, "Db")
			So(reqs[1].Method, ShouldEqual, "testEcho2")
			So(string(reqs[1].Data), ShouldEqual, `["Hello", 1, 2, 3, 4, null, null]`)
			So(reqs[1].Tid, ShouldEqual, 2)
			So(reqs[1].Type, ShouldEqual, "rpc")

			Convey("which is concurrently processed into 2 responses with correct fields", func() {
				t1 := time.Now()
				resps := provider.processRequests(nil, nil, reqs)
				t2 := time.Now()
				So(t2.Sub(t1), ShouldBeLessThan, 50*time.Millisecond)
				So(len(resps), ShouldEqual, 2)

				testEcho1Resp := getResponseByTid(resps, 1)
				So(testEcho1Resp.Message, ShouldBeNil)
				So(testEcho1Resp.Type, ShouldEqual, "rpc")
				So(testEcho1Resp.Action, ShouldEqual, "Db")
				So(testEcho1Resp.Method, ShouldEqual, "testEcho1")
				So(testEcho1Resp.Result, ShouldEqual, "Hello!")
				So(testEcho1Resp.Tid, ShouldEqual, 1)

				testEcho2Resp := getResponseByTid(resps, 2)
				So(testEcho2Resp.Message, ShouldBeNil)
				So(testEcho2Resp.Type, ShouldEqual, "rpc")
				So(testEcho2Resp.Action, ShouldEqual, "Db")
				So(testEcho2Resp.Method, ShouldEqual, "testEcho2")
				So(testEcho2Resp.Result, ShouldEqual, "Hello12340")
				So(testEcho2Resp.Tid, ShouldEqual, 2)
				Convey("which is serialized correctly", func() {
					s, err := json.Marshal(resps)
					So(err, ShouldBeNil)
					So(string(s), ShouldContainSubstring, `{"type":"rpc","tid":1,"action":"Db","method":"testEcho1","result":"Hello!"}`)
					So(string(s), ShouldContainSubstring, `{"type":"rpc","tid":2,"action":"Db","method":"testEcho2","result":"Hello12340"}`)
				})
			})
		})
	})

	Convey("Exception methods call", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))
		reqs := mustDecodeTransaction(strings.NewReader(`[{"action":"Db","method":"testException1","data":null,"type":"rpc","tid":1},{"action":"Db","method":"testException2","data":null,"type":"rpc","tid":2},{"action":"Db","method":"testException3","data":null,"type":"rpc","tid":3},{"action":"Db","method":"testException4","data":null,"type":"rpc","tid":4}]`))
		Convey("processed with 4 responses", func() {
			resps := provider.processRequests(nil, nil, reqs)
			So(len(resps), ShouldEqual, 4)
			Convey("with null results each", func() {
				for _, resp := range resps {
					So(resp.Result, ShouldBeNil)
				}
			})
			Convey("with exception type each", func() {
				for _, resp := range resps {
					So(resp.Type, ShouldEqual, "exception")
				}
			})
			Convey("with correct message each", func() {
				for _, resp := range resps {
					So(*resp.Message, ShouldContainSubstring, "Error example #")
				}
			})
		})
	})

	Convey("Get records", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))
		reqs := mustDecodeTransaction(strings.NewReader(`{"action":"Db","method":"getRecords","data":[{"page":1,"start":0,"limit":25,"sort":[{"property":"text","direction":"ASC"}]}],"type":"rpc","tid":1}`))
		Convey("processed with correct result", func() {
			resps := provider.processRequests(nil, nil, reqs)
			So(len(resps), ShouldEqual, 1)
			So(resps[0].Message, ShouldBeNil)
			So(resps[0].Type, ShouldEqual, "rpc")
			So(resps[0].Result, ShouldEqual, `model= page=1 start=0 limit=25 sort=[{text ASC}]`)
		})
	})

	Convey("Request with time", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))
		reqs := mustDecodeTransaction(strings.NewReader(`{"action":"Db","method":"testTime","data":[{"timestamp":"2009-11-10T23:00:00Z"}],"type":"rpc","tid":1}`))
		Convey("processed with correct result", func() {
			resps := provider.processRequests(nil, nil, reqs)
			So(len(resps), ShouldEqual, 1)
			if resps[0].Message != nil {
				So(*resps[0].Message, ShouldBeEmpty)
			}
			So(resps[0].Message, ShouldBeNil)
			So(resps[0].Type, ShouldEqual, "rpc")
			So(resps[0].Result, ShouldEqual, `2009-11-10T23:00:00Z`)
		})
	})

	Convey("Context setting", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))
		reqs := mustDecodeTransaction(strings.NewReader(`{"action":"Db","method":"test","data":null,"type":"rpc","tid":1}`))
		resps := provider.processRequests(gcontext.Set(&web.C{
			URLParams: map[string]string{"test": "test1"},
			Env: map[interface{}]interface{}{
				"user": "******",
			},
		}, context.Background()), &http.Request{Host: "test2"}, reqs)
		So(len(resps), ShouldEqual, 1)
		So(resps[0].Message, ShouldBeNil)
		So(resps[0].Type, ShouldEqual, "rpc")
		So(resps[0].Result, ShouldEqual, "test1TestUsertest2")
	})

	Convey("HTTP handlers", t, func() {
		provider := NewProvider()
		provider.Debug(providerDebug)
		provider.Profile(providerProfile)
		provider.RegisterAction(reflect.TypeOf(Db{}))

		mux := web.New()
		mux.Use(gcontext.Middleware)
		mux.Use(func(c *web.C, h http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				c.Env["user"] = "******"
				h.ServeHTTP(w, r)
			})
		})
		mux.Get(provider.URL, API(provider))
		mux.Post(provider.URL, func(c web.C, w http.ResponseWriter, r *http.Request) {
			ActionsHandlerCtx(provider)(gcontext.FromC(c), w, r)
		})
		mux.Post("/directapi2", ActionsHandler(provider))
		srv := httptest.NewServer(mux)
		defer srv.Close()

		Convey("API info request", func() {
			res, err := http.Get(srv.URL + provider.URL)
			Convey("should be processed without error", func() {
				So(err, ShouldBeNil)
				Convey("have correct content type", func() {
					So(res.Header.Get("Content-Type"), ShouldEqual, "text/javascript; charset=utf-8")
					Convey("and return expected body", func() {
						body, err := ioutil.ReadAll(res.Body)
						res.Body.Close()
						So(err, ShouldBeNil)
						So(string(body), ShouldEqual, `Ext.ns("DirectApi");DirectApi.REMOTE_API={"type":"remoting","url":"/directapi","namespace":"DirectApi","timeout":30000,"actions":{"Db":[{"name":"getRecords","len":1},{"name":"test","len":0},{"name":"testEcho1","len":1},{"name":"testEcho2","len":7},{"name":"testException1","len":0},{"name":"testException2","len":0},{"name":"testException3","len":0},{"name":"testException4","len":0},{"name":"testTime","len":1},{"name":"updateBasicInfo","formHander":true}]}}`)
					})
				})
			})
		})

		Convey("API handler request with context", func() {
			res, err := http.Post(srv.URL+provider.URL, "application/json", strings.NewReader(`{"action":"Db","method":"test","data":null,"type":"rpc","tid":33}`))
			Convey("should be processed without error", func() {
				So(err, ShouldBeNil)
				Convey("have correct content type", func() {
					So(res.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
					Convey("and return expected body", func() {
						body, err := ioutil.ReadAll(res.Body)
						res.Body.Close()
						So(err, ShouldBeNil)
						fmt.Println(string(body))
						So(MatchesRegexp(`\[{"type":"rpc","tid":33,"action":"Db","method":"test","result":"TestUser127\.0\.0\.1:\d+"}]`).Matches(string(body)), ShouldBeNil)
					})
				})
			})
		})

		Convey("API handler request without context", func() {
			res, err := http.Post(srv.URL+"/directapi2", "application/json", strings.NewReader(`{"action":"Db","method":"test","data":null,"type":"rpc","tid":33}`))
			Convey("should be processed without error", func() {
				So(err, ShouldBeNil)
				Convey("have correct content type", func() {
					So(res.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
					Convey("and return expected body", func() {
						body, err := ioutil.ReadAll(res.Body)
						res.Body.Close()
						So(err, ShouldBeNil)
						fmt.Println(string(body))
						So(MatchesRegexp(`\[{"type":"rpc","tid":33,"action":"Db","method":"test","result":"127\.0\.0\.1:\d+"}]`).Matches(string(body)), ShouldBeNil)
					})
				})
			})
		})

		Convey("API handler request to exception method", func() {
			res, err := http.Post(srv.URL+provider.URL, "application/json", strings.NewReader(`{"action":"Db","method":"testException1","data":null,"type":"rpc","tid":40}`))
			Convey("should be processed without error", func() {
				So(err, ShouldBeNil)
				Convey("have correct content type", func() {
					So(res.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
					Convey("and return expected body", func() {
						body, err := ioutil.ReadAll(res.Body)
						res.Body.Close()
						bodyString := strings.TrimSuffix(string(body), "\n")
						So(err, ShouldBeNil)
						fmt.Println(bodyString)
						So(bodyString, ShouldEqual, `[{"type":"exception","tid":40,"action":"Db","method":"testException1","message":"Error example #1"}]`)
					})
				})
			})
		})

		Convey("API handler request to form handler", func() {
			res, err := http.Post(srv.URL+"/directapi", "application/x-www-form-urlencoded; charset=UTF-8", strings.NewReader(`extTID=1&extAction=Db&extMethod=updateBasicInfo&extType=rpc&extUpload=false&foo=bar&uid=34&name=Aaron%20Conran&email=aaron%40sencha1.com&company=Sencha%20Inc.`))
			Convey("should be processed without error", func() {
				So(err, ShouldBeNil)
				Convey("have correct content type", func() {
					So(res.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
					Convey("and return expected body", func() {
						body, err := ioutil.ReadAll(res.Body)
						res.Body.Close()
						bodyString := strings.TrimSuffix(string(body), "\n")
						So(err, ShouldBeNil)
						fmt.Println(bodyString)
						So(bodyString, ShouldEqual, `{"type":"rpc","tid":1,"action":"Db","method":"updateBasicInfo","result":{"success":true}}`)
					})
				})
			})
		})

		Convey("API handler request to form handler returning validation error", func() {
			res, err := http.Post(srv.URL+"/directapi", "application/x-www-form-urlencoded; charset=UTF-8", strings.NewReader(`extTID=1&extAction=Db&extMethod=updateBasicInfo&extType=rpc&extUpload=false&foo=bar&uid=34&name=Aaron%20Conran&email=aaron%40sencha.com&company=Sencha%20Inc.`))
			Convey("should be processed without error", func() {
				So(err, ShouldBeNil)
				Convey("have correct content type", func() {
					So(res.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
					Convey("and return expected body", func() {
						body, err := ioutil.ReadAll(res.Body)
						res.Body.Close()
						bodyString := strings.TrimSuffix(string(body), "\n")
						So(err, ShouldBeNil)
						fmt.Println(bodyString)
						So(bodyString, ShouldEqual, `{"type":"rpc","tid":1,"action":"Db","method":"updateBasicInfo","result":{"errors":{"email":"already exists"},"success":false}}`)
					})
				})
			})
		})
	})
}