func main() { pid := syscall.Getpid() flag.Parse() // create the pipeline pipeline := falcore.NewPipeline() pipeline.Upstream.PushBack(falcore.NewRequestFilter(Filter)) // create the server with the pipeline srv := falcore.NewServer(8090, pipeline) // if passed the socket file descriptor, setup the listener that way // if you don't have it, the default is to create the socket listener // with the data passed to falcore.NewServer above (happens in ListenAndServer()) if *socketFd != -1 { // I know I'm a child process if I get here so I can signal the parent when I'm ready to take over go childReady(srv) fmt.Printf("%v Got socket FD: %v\n", pid, *socketFd) srv.FdListen(*socketFd) } // using signals to manage the restart lifecycle go handleSignals(srv) // start the server // this is normally blocking forever unless you send lifecycle commands fmt.Printf("%v Starting Listener on 8090\n", pid) if err := srv.ListenAndServe(); err != nil { fmt.Printf("%v Could not start server: %v", pid, err) } fmt.Printf("%v Exiting now\n", pid) }
// NewLandingFilter generates a Falcore RequestFilter that produces a simple // landing page. func NewLandingFilter() falcore.RequestFilter { log().Debug("registering a new landing filter") return falcore.NewRequestFilter( func(req *falcore.Request) *http.Response { log().Info("running landing filter") return falcore.StringResponse( req.HttpRequest, 200, nil, "<html><head><title>"+ "Pullcord Landing Page"+ "</title></head><body><h1>"+ "Pullcord Landing Page"+ "</h1><p>"+ "This is the landing page for Pullcord, "+ "a reverse proxy for cloud-based web apps "+ "that allows the servers the web apps run on "+ "to be turned off when not in use."+ "</p><p>"+ "If you are unsure of how to proceed, "+ "please contact the site administrator."+ "</p></body></html>", ) }, ) }
func main() { // parse command line options flag.Parse() // setup pipeline pipeline := falcore.NewPipeline() // upstream filters // Serve index.html for root requests pipeline.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { if req.HttpRequest.URL.Path == "/" { req.HttpRequest.URL.Path = "/index.html" } return nil })) // Serve files pipeline.Upstream.PushBack(&filter.FileFilter{ BasePath: *path, }) // downstream pipeline.Downstream.PushBack(filter.NewCompressionFilter(nil)) // setup server server := falcore.NewServer(*port, pipeline) // start the server // this is normally blocking forever unless you send lifecycle commands if err := server.ListenAndServe(); err != nil { fmt.Println("Could not start server:", err) } }
func init() { go func() { // falcore setup pipeline := falcore.NewPipeline() pipeline.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { for _, data := range eserverData { if data.path == req.HttpRequest.URL.Path { header := make(http.Header) header.Set("Etag", data.etag) if data.chunked { buf := new(bytes.Buffer) buf.Write(data.body) res := falcore.SimpleResponse(req.HttpRequest, data.status, header, -1, ioutil.NopCloser(buf)) res.TransferEncoding = []string{"chunked"} return res } else { return falcore.StringResponse(req.HttpRequest, data.status, header, string(data.body)) } } } return falcore.StringResponse(req.HttpRequest, 404, nil, "Not Found") })) pipeline.Downstream.PushBack(new(EtagFilter)) esrv = falcore.NewServer(0, pipeline) if err := esrv.ListenAndServe(); err != nil { panic("Could not start falcore") } }() }
func TestUpstreamThrottle(t *testing.T) { // Start a test server sleepPipe := falcore.NewPipeline() sleepPipe.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { time.Sleep(time.Second) return falcore.StringResponse(req.HttpRequest, 200, nil, "OK") })) sleepSrv := falcore.NewServer(0, sleepPipe) go func() { sleepSrv.ListenAndServe() }() <-sleepSrv.AcceptReady // Build Upstream up := NewUpstream(NewUpstreamTransport("localhost", sleepSrv.Port(), 0, nil)) // pipe := falcore.NewPipeline() // pipe.Upstream.PushBack(up) resCh := make(chan *http.Response, 10) var i int64 = 1 for ; i < 12; i++ { start := time.Now() up.SetMaxConcurrent(i) for j := 0; j < 10; j++ { go func() { req, _ := http.NewRequest("GET", "/", nil) _, res := falcore.TestWithRequest(req, up, nil) resCh <- res // fmt.Println("OK") }() } for j := 0; j < 10; j++ { res := <-resCh if res.StatusCode != 200 { t.Fatalf("Error: %v", res) } } duration := time.Since(start) seconds := float64(duration) / float64(time.Second) goal := math.Ceil(10.0 / float64(i)) // fmt.Println(i, "Time:", seconds, "Goal:", goal) if seconds < goal { t.Errorf("%v: Too short: %v < %v", i, seconds, goal) } } }
func TestUpstreamTimeout(t *testing.T) { // Start a test server sleepPipe := falcore.NewPipeline() sleepPipe.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { tt, _ := strconv.Atoi(req.HttpRequest.URL.Query().Get("time")) b, _ := strconv.Atoi(req.HttpRequest.URL.Query().Get("body")) bl, _ := strconv.Atoi(req.HttpRequest.URL.Query().Get("bl")) time.Sleep(time.Duration(tt)) pr, pw := io.Pipe() go func() { buf := make([]byte, 1024) for i := 0; i < bl; i++ { <-time.After(time.Duration(b)) pw.Write(buf) } pw.Close() }() return falcore.SimpleResponse(req.HttpRequest, 200, nil, int64(bl*1024), pr) })) sleepSrv := falcore.NewServer(0, sleepPipe) go func() { sleepSrv.ListenAndServe() }() <-sleepSrv.AcceptReady // Build Upstream up := NewUpstream(NewUpstreamTransport("localhost", sleepSrv.Port(), time.Second, nil)) for _, test := range upstreamTimeoutTestData { req, _ := http.NewRequest("GET", fmt.Sprintf("http://localhost/test?time=%v&body=%v&bl=%v", int64(test.Time), int64(test.BodyTime), test.BodyLen), nil) _, res := falcore.TestWithRequest(req, up, nil) if res.StatusCode != test.StatusCode { t.Errorf("%v Expected status %v Got %v", test.Name, test.StatusCode, res.StatusCode) } if res.StatusCode == 200 { i, _ := io.Copy(ioutil.Discard, res.Body) res.Body.Close() if i != (test.BodyLen * 1024) { t.Errorf("%v Expected body len %v Got %v", test.Name, (test.BodyLen * 1024), i) } } } }
func init() { go func() { // falcore setup pipeline := falcore.NewPipeline() pipeline.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { for _, data := range eserverData { if data.path == req.HttpRequest.URL.Path { header := make(http.Header) header.Set("Etag", data.etag) return falcore.StringResponse(req.HttpRequest, data.status, header, string(data.body)) } } return falcore.StringResponse(req.HttpRequest, 404, nil, "Not Found") })) pipeline.Downstream.PushBack(new(EtagFilter)) esrv = falcore.NewServer(0, pipeline) if err := esrv.ListenAndServe(); err != nil { panic("Could not start falcore") } }() }
func validGetRequest() (req *falcore.Request) { tmp, _ := http.NewRequest("GET", "/hello", bytes.NewBuffer(make([]byte, 0))) req, _ = falcore.TestWithRequest(tmp, falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { return nil }), nil) return }
func TestPassthruLoginPage(t *testing.T) { /* setup */ testUser := "******" testPassword := "******" downstreamFilter := falcore.NewRequestFilter( func(request *falcore.Request) *http.Response { return falcore.StringResponse( request.HttpRequest, 200, nil, "<html><body><p>logged in</p></body></html>", ) }, ) sessionHandler := NewMinSessionHandler( "testSessionHandler", "/", "example.com", ) hash, err := GetPbkdf2Hash(testPassword, Pbkdf2MinIterations) assert.NoError(t, err) passwordChecker := InMemPwdStore{ map[string]*Pbkdf2Hash{ testUser: hash, }, } request1, err := http.NewRequest("GET", "/", nil) assert.NoError(t, err) /* run */ handler := &LoginHandler{ "testLoginHandler", &passwordChecker, downstreamFilter, } filter := &CookiemaskFilter{ sessionHandler, handler, falcore.NewRequestFilter( func(request *falcore.Request) *http.Response { return internalServerError(request) }, ), } _, response1 := falcore.TestWithRequest(request1, filter, nil) assert.Equal(t, 200, response1.StatusCode) assert.NotEmpty(t, response1.Header["Set-Cookie"]) content1, err := ioutil.ReadAll(response1.Body) assert.NoError(t, err) htmlRoot, err := html.Parse(bytes.NewReader(content1)) assert.NoError(t, err) xsrfToken, err := getXsrfToken(htmlRoot, "xsrf-"+handler.Identifier) assert.NoError(t, err) postdata2 := url.Values{} postdata2.Add("xsrf-"+handler.Identifier, xsrfToken) postdata2.Add("username-"+handler.Identifier, testUser) postdata2.Add("password-"+handler.Identifier, testPassword) request2, err := http.NewRequest( "POST", "/", strings.NewReader(postdata2.Encode()), ) request2.Header.Set( "Content-Type", "application/x-www-form-urlencoded", ) assert.NoError(t, err) for _, cke := range response1.Cookies() { request2.AddCookie(cke) } _, response2 := falcore.TestWithRequest(request2, filter, nil) assert.Equal(t, 200, response2.StatusCode) content2, err := ioutil.ReadAll(response2.Body) assert.NoError(t, err) assert.True( t, strings.Contains(string(content2), "logged in"), "content is: "+string(content2), ) request3, err := http.NewRequest("GET", "/", nil) assert.NoError(t, err) for _, cke := range response1.Cookies() { request3.AddCookie(cke) } _, response3 := falcore.TestWithRequest(request3, filter, nil) /* check */ assert.Equal(t, 200, response3.StatusCode) content3, err := ioutil.ReadAll(response3.Body) assert.NoError(t, err) assert.True( t, strings.Contains(string(content3), "logged in"), "content is: "+string(content3), ) }
func TestInitialLoginPage(t *testing.T) { /* setup */ testUser := "******" testPassword := "******" downstreamFilter := falcore.NewRequestFilter( func(request *falcore.Request) *http.Response { return falcore.StringResponse( request.HttpRequest, 200, nil, "<html><body><p>logged in</p></body></html>", ) }, ) sessionHandler := NewMinSessionHandler( "testSessionHandler", "/", "example.com", ) hash, err := GetPbkdf2Hash(testPassword, Pbkdf2MinIterations) assert.NoError(t, err) passwordChecker := InMemPwdStore{ map[string]*Pbkdf2Hash{ testUser: hash, }, } request, err := http.NewRequest("GET", "/", nil) assert.NoError(t, err) /* run */ handler := &LoginHandler{ "testLoginHandler", &passwordChecker, downstreamFilter, } filter := &CookiemaskFilter{ sessionHandler, handler, falcore.NewRequestFilter( func(request *falcore.Request) *http.Response { return internalServerError(request) }, ), } _, response := falcore.TestWithRequest(request, filter, nil) /* check */ assert.Equal(t, 200, response.StatusCode) content, err := ioutil.ReadAll(response.Body) assert.NoError(t, err) assert.True( t, strings.Contains(string(content), "xsrf-testLoginHandler"), "content is: "+string(content), ) assert.False( t, strings.Contains(string(content), "error"), "content is: "+string(content), ) assert.NotEmpty(t, response.Header["Set-Cookie"]) }
} var requiredHeaders = falcore.NewResponseFilter(func(req *falcore.Request, res *http.Response) { res.Header.Set("Server", "falcore") res.Header.Set("Date", time.Now().Format(time.RFC1123)) }) var applicationJson = http.Header{"Content-Type": []string{"application/json"}} var textPlain = http.Header{"Content-Type": []string{"text/plain"}} var textHtml = http.Header{"Content-Type": []string{"text/html"}} // Test 1: JSON serialization var jsonFilter = falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { if req.HttpRequest.URL.Path == "/json" { resp, _ := responder.JSONResponse(req.HttpRequest, 200, applicationJson, &Message{helloWorldString}) return resp } return nil }) // Test 2: Single database query var dbFilter = falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { if req.HttpRequest.URL.Path == "/db" { var world World err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber) if err != nil { log.Fatalf("Error scanning world row: %s", err.Error()) } resp, _ := responder.JSONResponse(req.HttpRequest, 200, applicationJson, &world) return resp
) // Command line options var ( port = flag.Int("port", 8000, "the port to listen on") ) func main() { // parse command line options flag.Parse() // setup pipeline pipeline := falcore.NewPipeline() // upstream pipeline.Upstream.PushBack(helloFilter) // setup server server := falcore.NewServer(*port, pipeline) // start the server // this is normally blocking forever unless you send lifecycle commands if err := server.ListenAndServe(); err != nil { fmt.Println("Could not start server:", err) } } var helloFilter = falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { return falcore.StringResponse(req.HttpRequest, 200, nil, "hello world!") })
} var cookieMaskTestPage = falcore.NewRequestFilter( func(req *falcore.Request) *http.Response { var content = "<html><body><h1>cookies</h1><ul>" for _, cke := range req.HttpRequest.Cookies() { content += "<li class=\"cke\">" + cke.String() + "</li>" } content += "</ul><h1>context</h1><ul>" sesh := req.Context["session"].(*MinSession) for key, val := range sesh.GetValues() { content += "<li class=\"sesh\">" + key + ": " + gostring(val) + "</li>" } content += "</ul></body></html>" return falcore.StringResponse( req.HttpRequest, 200, nil, content, ) }, ) var errorPage = falcore.NewRequestFilter(
func TestUpstreamThrottle(t *testing.T) { // Build a thing for var started = make(chan chan bool, REQ_COUNT+1) // Start a test server sleepPipe := falcore.NewPipeline() sleepPipe.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response { // get chan // j, _ := strconv.Atoi(req.HttpRequest.URL.Query().Get("j")) // fmt.Println(req.HttpRequest.URL, j) c := make(chan bool) started <- c // wait on chan <-c // fmt.Println("DONE") return falcore.StringResponse(req.HttpRequest, 200, nil, "OK") })) sleepSrv := falcore.NewServer(0, sleepPipe) defer sleepSrv.StopAccepting() go func() { sleepSrv.ListenAndServe() }() <-sleepSrv.AcceptReady // Build Upstream up := NewUpstream(NewUpstreamTransport("localhost", sleepSrv.Port(), 0, nil)) // pipe := falcore.NewPipeline() // pipe.Upstream.PushBack(up) resCh := make(chan *http.Response, REQ_COUNT) var i int64 = 1 for ; i < 12; i++ { // fmt.Println("Testing with limit", i) up.SetMaxConcurrent(i) for j := 0; j < REQ_COUNT; j++ { var jj = j go func() { // fmt.Println("STARTING") req, _ := http.NewRequest("GET", fmt.Sprintf("http://localhost/foo?j=%v", jj), nil) _, res := falcore.TestWithRequest(req, up, nil) res.Body.Close() resCh <- res // fmt.Println("OK") }() } for j := 0; j < REQ_COUNT; j++ { // make sure we haven't gone over the limit // fmt.Println(i, len(started)) if r := int64(len(started)); r > i { t.Errorf("%v: Over the limit: %v", i, r) } // send a finish signal (<-started) <- true // collect the result res := <-resCh if res.StatusCode != 200 { t.Fatalf("Error: %v", res) } } } }