1. Sean Russell
  2. go-fastweb

Commits

Sean Russell  committed 0ff467a

Use Go's fcgi, rather than go-fastcgi

  • Participants
  • Parent commits b13e283
  • Branches default

Comments (0)

Files changed (2)

File fastweb.go

View file
  • Ignore whitespace
 package fastweb
 
 import (
-	"bufio"
 	"bytes"
-	"code.google.com/p/go-fastcgi"
-	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
 	"log"
 	"math/rand"
+	"net"
 	"net/url"
+	"net/http"
+	"path/filepath"
+	//"net/http/fcgi"
 	"os"
 	"reflect"
 	"regexp"
 type Application struct {
 	controllerMap     map[string]*controllerInfo
 	defaultController string
+	fileServer        http.Handler
 }
 
 type env struct {
 	action      string
 	laction     string
 	params      []string
-	request     *fastcgi.Request
+	request     *http.Request
+	response    http.ResponseWriter
 	body        string
-	form        map[string][]string
-	upload      map[string][](*Upload)
-	cookies     map[string]string
-}
-
-type Upload struct {
-	File     *os.File
-	Filename string
 }
 
 type cookie struct {
 	LName       string
 	Action      string
 	LAction     string
-	Params      []string
 	PageTitle   string
 	Layout      string
 	ContentType string
 	Body        string
-	Form        map[string][]string
-	Upload      map[string][]*Upload
-	Cookies     map[string]string
 	Session     *Session
-	setCookies  map[string]*cookie
 	ctxt        ControllerInterface
-	Request     *fastcgi.Request
+	Request     *http.Request
+	Response    http.ResponseWriter
 	preRenered  bool
 }
 
 	c.Action = env.action
 	c.LAction = env.laction
 	c.Path = env.path
-	c.Params = env.params
 	c.Request = env.request
+	c.Response = env.response
 	c.Body = env.body
-	c.Form = env.form
-	c.Upload = env.upload
-	c.Cookies = env.cookies
 }
 
 func (c *Controller) PreFilter() {}
 	}
 }
 
-func (c *Controller) preRender() {
-	if !c.preRenered {
-		io.WriteString(c.Request.Stdout, "Content-Type: "+c.ContentType+"\r\n")
-
-		if c.setCookies != nil {
-			for k, ck := range c.setCookies {
-				s := "Set-Cookie: " + k + "=" + url.QueryEscape(ck.value)
-				if !ck.expire.IsZero() {
-					s += "; expire=" + ck.expire.Format(time.RFC1123)
-				}
-				if ck.path != "" {
-					s += "; path=" + ck.path
-				}
-				if ck.domain != "" {
-					s += "; path=" + ck.domain
-				}
-				if ck.secure {
-					s += "; secure"
-				}
-				if ck.httpOnly {
-					s += "; HttpOnly"
-				}
-				io.WriteString(c.Request.Stdout, s+"\r\n")
-			}
-		}
-
-		io.WriteString(c.Request.Stdout, "\r\n")
-		c.preRenered = true
-	}
-}
-
 func executeTemplate(fname string, t *Template, w io.Writer, data interface{}) {
 	e := t.Execute(w, data)
 	if e != nil {
 }
 
 func (c *Controller) RenderContent() string {
-	c.preRender()
-
 	fname := "views/" + c.LName + "/" + c.LAction + ".tpl"
 	t, e := loadTemplate(fname)
 	if e != nil {
 	}
 
 	if t != nil {
-		executeTemplate(fname, t, c.Request.Stdout, c.ctxt)
+		executeTemplate(fname, t, c.Response, c.ctxt)
 	}
 
 	return ""
 func (c *Controller) renderTemplate(fname string) {
 	t, e := loadTemplate(fname)
 	if e == nil {
-		executeTemplate(fname, t, c.Request.Stdout, c.ctxt)
+		executeTemplate(fname, t, c.Response, c.ctxt)
 	} else {
 		log.Printf("failed to load template %s: %s", fname, e)
 	}
 }
 
 func (c *Controller) Render() {
-	c.preRender()
-
 	if len(c.Layout) == 0 {
 		c.RenderContent()
 		return
 		log.Printf("failed to load layout template %s: %s", fname, e)
 		c.RenderContent()
 	} else {
-		executeTemplate(fname, t, c.Request.Stdout, c.ctxt)
+		executeTemplate(fname, t, c.Response, c.ctxt)
 	}
 }
 
 func (c *Controller) SetCookie(key string, value string) {
-	c.SetCookieFull(key, value, time.Time{}, "", "", false, false)
+	http.SetCookie(c.Response, &http.Cookie{
+		Name: key,
+		Value: value,
+		Path: "",
+		Domain: "",
+		Expires: time.Time{},
+		Secure: false,
+		HttpOnly: false,
+	})
 }
 
 func (c *Controller) SetCookieFull(key string, value string, expire time.Time, path string, domain string, secure bool, httpOnly bool) {
-	if c.setCookies == nil {
-		c.setCookies = make(map[string]*cookie)
-	}
-
-	c.setCookies[key] = &cookie{
-		value:    value,
-		expire:   expire,
-		path:     path,
-		domain:   domain,
-		secure:   secure,
-		httpOnly: httpOnly,
-	}
+	http.SetCookie(c.Response, &http.Cookie{
+		Name: key,
+		Value: value,
+		Path: path,
+		Domain: domain,
+		Expires: expire,
+		Secure: secure,
+		HttpOnly: httpOnly,
+	})
 }
 
 func (c *Controller) StartSession() {
 	typ string
 }
 
-func NewErrorHandler(e Error, r *fastcgi.Request) *ErrorHandler {
+func NewErrorHandler(e Error, response http.ResponseWriter, r *http.Request) *ErrorHandler {
 	eh := &ErrorHandler{
 		typ: e.Type(),
 	}
 	eh.Request = r
+	eh.Response = response
 	eh.Init()
 	eh.SetContext(eh)
 	return eh
 }
 
 func (eh *ErrorHandler) RenderContent() string {
-	eh.preRender()
-
 	fname := "views/errors/" + eh.typ + ".tpl"
 	t, e := loadTemplate(fname)
 	if e != nil {
 		default:
 			msg = "We're sorry, but there was an error processing your request. Please try again later."
 		}
-		fmt.Fprintf(eh.Request.Stdout, "%s", msg)
+		fmt.Fprintf(eh.Response, "%s", msg)
 	} else {
-		t.Execute(eh.Request.Stdout, eh)
-		executeTemplate(fname, t, eh.Request.Stdout, eh)
+		t.Execute(eh.Response, eh)
+		executeTemplate(fname, t, eh.Response, eh)
 	}
 
 	return ""
 	return nil, nil
 }
 
-func parseMultipartForm(m map[string][]string, u map[string][]*Upload, r *fastcgi.Request) error {
-	ct := r.Params["CONTENT_TYPE"]
-	a := boundaryRE.FindStringSubmatchIndex(ct)
-	if len(a) < 4 {
-		return errors.New("can't find boundary in content type")
-	}
-	b := ct[a[2]:a[3]]
-	md := newMultipartReader(r.Stdin, b)
-	md.readFirstLine()
-	for !md.finished() {
-		hdrs, e := md.readHeaders()
-		if e != nil {
-			return e
-		}
-		cd, ok := hdrs["Content-Disposition"]
-		if !ok {
-			return errors.New("can't find Content-Disposition")
-		}
-		name, ok := cd.attribs["name"]
-		if !ok {
-			return errors.New("can't find attrib 'name' in Content-Disposition")
-		}
-		filename, ok := cd.attribs["filename"]
-		if ok {
-			vec, ok := u[name]
-			if !ok {
-				vec = make([]*Upload, 1)
-				u[name] = vec
-			}
-
-			file, e := tempfile()
-			if e != nil {
-				return e
-			}
-			wr := bufio.NewWriter(file)
-			fname := file.Name()
-			md.readUntil(md.bd, true, func(b []byte) error {
-				if _, e := wr.Write(b); e != nil {
-					return e
-				}
-				return nil
-			})
-			wr.Flush()
-			// to flush (system) buffer, re-open immediately
-			file.Close()
-			file, _ = os.Open(fname)
-
-			vec = append(vec, &Upload{
-				File:     file,
-				Filename: filename,
-			})
-		} else {
-			vec, ok := m[name]
-			if !ok {
-				vec = make([]string, 1)
-				m[name] = vec
-			}
-			s, e := md.readBody()
-			if e != nil {
-				return e
-			}
-			vec = append(vec, s)
-		}
-	}
-	return nil
-}
-
-func parseForm(r *fastcgi.Request) (string, map[string][]string, map[string][]*Upload, error) {
-	m := make(map[string][]string)
-	u := make(map[string][]*Upload)
-	var body string
-
-	s := r.Params["QUERY_STRING"]
-	if s != "" {
-		e := parseKeyValueString(m, s)
-		if e != nil {
-			return body, nil, nil, e
-		}
-	}
-
-	if r.Params["REQUEST_METHOD"] == "POST" {
-		switch ct := r.Params["CONTENT_TYPE"]; true {
-		case strings.HasPrefix(ct, "application/x-www-form-urlencoded") && (len(ct) == 33 || ct[33] == ';'):
-			var b []byte
-			var e error
-			if b, e = ioutil.ReadAll(r.Stdin); e != nil {
-				return body, nil, nil, e
-			}
-			body = string(b)
-			e = parseKeyValueString(m, body)
-			if e != nil {
-				return body, nil, nil, e
-			}
-		case strings.HasPrefix(ct, "multipart/form-data"):
-			e := parseMultipartForm(m, u, r)
-			if e != nil {
-				return body, nil, nil, e
-			}
-		default:
-			log.Printf("unknown content type '%s'", ct)
-		}
-	}
-
-	form := make(map[string][]string)
-	for k, vec := range m {
-		form[k] = make([]string, len(vec))
-		copy(form[k], vec)
-	}
-
-	upload := make(map[string][]*Upload)
-	for k, vec := range u {
-		d := make([]*Upload, len(vec))
-		copy(d, vec)
-		v := make([]*Upload, len(d))
-		for i, u := range d {
-			v[i] = u
-		}
-		upload[k] = v
-	}
-
-	return body, form, upload, nil
-}
-
-func parseCookies(r *fastcgi.Request) (map[string]string, error) {
-	cookies := make(map[string]string)
-
-	if s, ok := r.Params["HTTP_COOKIE"]; ok {
-		var key string
-		phase := 0
-		j := 0
-		s += ";"
-		for i, c := range s {
-			switch phase {
-			case 0:
-				if c == '=' {
-					key = strings.TrimSpace(s[j:i])
-					j = i + 1
-					phase++
-				}
-			case 1:
-				if c == ';' {
-					v, e := url.QueryUnescape(s[j:i])
-					if e != nil {
-						return cookies, e
-					}
-					cookies[key] = v
-					phase = 0
-					j = i + 1
-				}
-			}
-		}
-	}
-
-	return cookies, nil
-}
-
-func (a *Application) getEnv(r *fastcgi.Request) *env {
+func (a *Application) getEnv(response http.ResponseWriter, r *http.Request) *env {
 	var params []string
 	var lname string
 	var laction string
 
-	path, _ := r.Params["REQUEST_URI"]
-	p := strings.SplitN(path, "?", 2)
-	if len(p) > 1 {
-		path = p[0]
-		r.Params["QUERY_STRING"] = p[1]
-	}
+	path := r.URL.Path
 
 	pparts := strings.Split(path, "/")
 	n := len(pparts)
 	name := titleCase(lname)
 	action := titleCase(laction)
 
-	body, form, upload, e := parseForm(r)
+	var body string
+	e := r.ParseMultipartForm(16000000)
 	if e != nil {
 		log.Printf("failed to parse form: %s", e.Error())
-	}
-
-	cookies, e := parseCookies(r)
-	if e != nil {
-		log.Printf("failed to parse cookies: %s", e.Error())
+	} else {
+		bodyReader := r.Body
+		data := make([]byte, 2048)
+		bodyReader.Read(data)
+		body = string(data)
 	}
 
 	return &env{
 		laction:     laction,
 		params:      params,
 		request:     r,
+		response:    response,
 		body:        body,
-		form:        form,
-		upload:      upload,
-		cookies:     cookies,
 	}
 }
 
-func (a *Application) route(r *fastcgi.Request) error {
-	env := a.getEnv(r)
+func (a *Application) route(response http.ResponseWriter, r *http.Request) error {
+	env := a.getEnv(response, r)
 
 	if env.controller == "" {
 		env.controller = a.defaultController
 
 	c.Init()
 	c.SetEnv(env)
-
 	c.PreFilter()
 
 	eval := minfo.method.Call(pv)[0]
 
 	c.SetContext(c)
 	c.Render()
-
 	c.CloseSession()
 
 	return nil
 }
 
-func (a *Application) Handle(r *fastcgi.Request) bool {
-	e := a.route(r)
+func (a *Application) ServeHTTP(response http.ResponseWriter, request *http.Request) {
+	e := a.route(response, request)
 
 	if e != nil {
-		var ee Error
-		if e, ok := e.(Error); ok {
-			ee = e
+		p := "htdocs/"+request.URL.Path
+		path := strings.Split(p, "/")
+		_, e := os.Stat(filepath.Join(path...))
+		if e != nil {
+			ee := NewError("Generic", e.Error())
+			log.Printf("%s", e.Error())
+			eh := NewErrorHandler(ee, response, request)
+			eh.Render()
 		} else {
-			ee = NewError("Generic", e.Error())
+			a.fileServer.ServeHTTP(response, request)
 		}
-		log.Printf("%s", e.Error())
-		eh := NewErrorHandler(ee, r)
-		eh.Render()
 	}
-
-	return true
 }
 
 func NewApplication() *Application {
 	return &Application{
 		controllerMap:     make(map[string]*controllerInfo),
 		defaultController: "Default",
+		fileServer: http.FileServer(http.Dir("htdocs")),
 	}
 }
 
 		mo := mt.Out(0)
 		switch mo.Kind() {
 		case reflect.Interface:
-			if mo.PkgPath() != "os" || mo.Name() != "Error" {
+			if mo.Name() != "error" {
 				continue
 			}
 		default:
 
 func (a *Application) Run(addr string) error {
 	rand.Seed(time.Now().UnixNano())
-	return fastcgi.RunStandalone(addr, a)
+	listener, err := net.Listen("tcp", addr)
+	if err != nil { panic(err) }
+	return http.Serve(listener, a)
 }

File session.go

View file
  • Ignore whitespace
 	var sid string
 LOAD:
 	for {
-		var ok bool
-		sid, ok = c.Cookies["fastweb_sessid"]
-		if !ok || len(sid) != 32 {
+		cookie, ok := c.Request.Cookie("fastweb_sessid")
+		sid = cookie.Value
+		if ok != nil || len(sid) != 32 {
 			break
 		}
 		for _, c := range sid {