summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2018-05-29 20:31:27 +0300
committerWolfy-J <[email protected]>2018-05-29 20:31:27 +0300
commit130da89a94f044fafed584ad5430b59991f317c7 (patch)
treeb6fac7a256b6089eb04ff6bacfbd138ada9382bc
parente45daa3bbfd5e95889d00ba3cf9ff6c95101bcb2 (diff)
updates for the server support
-rw-r--r--cmd/rr-php/cmd/serve.go22
-rw-r--r--server.go6
-rw-r--r--server/http.go159
3 files changed, 175 insertions, 12 deletions
diff --git a/cmd/rr-php/cmd/serve.go b/cmd/rr-php/cmd/serve.go
index cac830ac..dc15b6df 100644
--- a/cmd/rr-php/cmd/serve.go
+++ b/cmd/rr-php/cmd/serve.go
@@ -18,9 +18,10 @@ import (
"github.com/spf13/cobra"
"github.com/spiral/roadrunner"
"os/exec"
- "log"
"time"
"github.com/sirupsen/logrus"
+ "github.com/spiral/roadrunner/server"
+ "net/http"
)
func init() {
@@ -31,20 +32,20 @@ func init() {
}
func serveHandler(cmd *cobra.Command, args []string) {
- r := roadrunner.NewRouter(
+ rr := roadrunner.NewRouter(
func() *exec.Cmd {
return exec.Command("php", "/Users/wolfy-j/Projects/phpapp/webroot/index.php", "rr", "pipes")
},
roadrunner.NewPipeFactory(),
)
- err := r.Configure(roadrunner.Config{
+ err := rr.Configure(roadrunner.Config{
NumWorkers: 1,
AllocateTimeout: time.Minute,
DestroyTimeout: time.Minute,
})
- r.Observe(func(event int, ctx interface{}) {
+ rr.Observe(func(event int, ctx interface{}) {
logrus.Info(ctx)
})
@@ -52,10 +53,13 @@ func serveHandler(cmd *cobra.Command, args []string) {
panic(err)
}
- for i := 0; i < 10; i++ {
- r.Exec(&roadrunner.Payload{})
- }
-
- log.Print(r.Workers())
+ logrus.Info("serving")
+ http.ListenAndServe(":8080", server.NewHTTP(
+ server.HTTPConfig{
+ ServeStatic: true,
+ Root: "/Users/wolfy-j/Projects/phpapp/webroot",
+ },
+ rr,
+ ))
}
diff --git a/server.go b/server.go
index 829d0ceb..d873da63 100644
--- a/server.go
+++ b/server.go
@@ -43,7 +43,7 @@ func NewRouter(cmd func() *exec.Cmd, factory Factory) *Server {
}
}
-// Configure configures underlying pool and destroys it's previous version if any
+// Configure configures underlying pool and destroys it's previous version if any.
func (r *Server) Configure(cfg Config) error {
r.mu.Lock()
previous := r.pool
@@ -58,8 +58,8 @@ func (r *Server) Configure(cfg Config) error {
r.mu.Lock()
- r.pool.Observe(r.poolObserver)
r.cfg, r.pool = cfg, pool
+ r.pool.Observe(r.poolObserver)
r.mu.Unlock()
@@ -135,7 +135,7 @@ func (r *Server) throw(event int, ctx interface{}) {
}
}
-// Observe pool events
+// Observe pool events.
func (r *Server) poolObserver(event int, ctx interface{}) {
// bypassing to user specified observer
r.throw(event, ctx)
diff --git a/server/http.go b/server/http.go
new file mode 100644
index 00000000..3d8855a4
--- /dev/null
+++ b/server/http.go
@@ -0,0 +1,159 @@
+package server
+
+import (
+ "github.com/spiral/roadrunner"
+ "net/http"
+ "strings"
+ "path"
+ "github.com/sirupsen/logrus"
+ "os"
+ "path/filepath"
+ "encoding/json"
+)
+
+var (
+ excludeFiles = []string{".php", ".htaccess"}
+)
+
+type Request struct {
+ Protocol string `json:"protocol"`
+ Uri string `json:"uri"`
+ Method string `json:"method"`
+ Headers http.Header `json:"headers"`
+ Cookies map[string]string `json:"cookies"`
+ RawQuery string `json:"rawQuery"`
+}
+
+// Configures http rr
+type HTTPConfig struct {
+ // ServeStatic enables static file serving from desired root directory.
+ ServeStatic bool
+
+ // Root directory, required when ServeStatic set to true.
+ Root string
+}
+
+// HTTP serves http connections to underlying PHP application using PSR-7 protocol. Context will include request headers,
+// parsed files and query, payload will include parsed form data (if any) - todo: do we need to do that?.
+type HTTP struct {
+ cfg HTTPConfig
+ root http.Dir
+ rr *roadrunner.Server
+}
+
+func NewHTTP(cfg HTTPConfig, server *roadrunner.Server) *HTTP {
+ h := &HTTP{cfg: cfg, rr: server}
+ if cfg.ServeStatic {
+ h.root = http.Dir(h.cfg.Root)
+ }
+
+ return h
+}
+
+// ServeHTTP serve using PSR-7 requests passed to underlying application.
+func (h *HTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) () {
+ if h.cfg.ServeStatic && h.serveStatic(w, r) {
+ // serving static files
+ return
+ }
+
+ // WHAT TO PUT TO BODY?
+ p, err := h.buildPayload(r)
+ rsp, err := h.rr.Exec(p)
+
+ if err != nil {
+ w.Write([]byte(err.Error()))
+ return
+ }
+
+ // wrapping the response
+
+ w.Header().Add("content-type", "text/html;charset=UTF-8")
+ w.Write(rsp.Body)
+}
+
+// serveStatic attempts to serve static file and returns true in case of success, will return false in case if file not
+// found, not allowed or on read error.
+func (h *HTTP) serveStatic(w http.ResponseWriter, r *http.Request) bool {
+ fpath := r.URL.Path
+ if !strings.HasPrefix(fpath, "/") {
+ fpath = "/" + fpath
+ }
+ fpath = path.Clean(fpath)
+
+ if isForbidden(fpath) {
+ logrus.Warningf("attempt to access forbidden file %s", fpath)
+ return false
+ }
+
+ f, err := h.root.Open(fpath)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ // rr or access error
+ logrus.Error(err)
+ }
+
+ return false
+ }
+ defer f.Close()
+
+ d, err := f.Stat()
+ if err != nil {
+ // rr error
+ logrus.Error(err)
+ return false
+ }
+
+ if d.IsDir() {
+ // we are not serving directories
+ return false
+ }
+
+ http.ServeContent(w, r, d.Name(), d.ModTime(), f)
+ return true
+}
+
+// todo: add files support
+func (h *HTTP) buildPayload(r *http.Request) (*roadrunner.Payload, error) {
+ request := Request{
+ Protocol: r.Proto,
+ Uri: r.URL.String(),
+ Method: r.Method,
+ Headers: r.Header,
+ Cookies: make(map[string]string),
+ RawQuery: r.URL.RawQuery,
+ }
+
+ r.ParseMultipartForm(1000000000)
+
+ logrus.Print(r.MultipartForm.Value)
+ logrus.Print(r.MultipartForm.File["kkk"][0].Header)
+ logrus.Print(r.MultipartForm.File["kkk"][0].Filename)
+ logrus.Print(r.Form)
+
+ // cookies
+ for _, c := range r.Cookies() {
+ request.Cookies[c.Name] = c.Value
+ }
+
+ data, _ := json.Marshal(request)
+
+ logrus.Info(string(data))
+
+ return &roadrunner.Payload{
+ Context: data,
+ Body: []byte("lol"),
+ }, nil
+}
+
+// isForbidden returns true if file has forbidden extension.
+func isForbidden(path string) bool {
+ ext := strings.ToLower(filepath.Ext(path))
+ for _, exl := range excludeFiles {
+ if ext == exl {
+ return true
+ }
+ }
+
+ return false
+}