Esempio n. 1
0
func TestClient_NewRequestWithLimit(t *testing.T) {

	limit := uint32(rand.Int31n(100) + 10)
	t.Logf("random limit: %d", limit)

	c := gofast.NewClient(nil, limit)

	for i := uint32(0); i < limit; i++ {
		r := c.NewRequest(nil)
		if want, have := uint16(i), r.ID; want != have {
			t.Errorf("expected %d, got %d", want, have)
		}
	}

	// test if client can allocate new request
	// when all request ids are already allocated
	newAlloc := make(chan uint16)
	go func(c gofast.Client, newAlloc chan<- uint16) {
		r := c.NewRequest(nil) // should be blocked before releaseID call
		newAlloc <- r.ID
	}(c, newAlloc)

	select {
	case reqID := <-newAlloc:
		t.Errorf("unexpected new allocation: %d", reqID)
	case <-time.After(time.Millisecond * 100):
		t.Log("blocks as expected")
	}

	// now, release a random ID
	released := uint16(rand.Int31n(int32(limit)))
	go func(c gofast.Client, released uint16) {
		c.ReleaseID(released)
	}(c, released)

	select {
	case reqID := <-newAlloc:
		if want, have := released, reqID; want != have {
			t.Errorf("expected %d, got %d", want, have)
		}
	case <-time.After(time.Millisecond * 100):
		t.Errorf("unexpected blocking")
	}
}
Esempio n. 2
0
// FastCGIPass pass the request to fastcgi socket
func (f FastCGI) FastCGIPass(w http.ResponseWriter, r *http.Request) {
	var scriptName, pathInfo, scriptFileName string

	conn, err := net.Dial(f.Network, f.Addr)
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusBadGateway)
		return
	}

	defer conn.Close()

	client := gofast.NewClient(conn, 20)

	urlPath := r.URL.Path
	if f.URLPrefix != "" {
		urlPath = strings.Replace(r.URL.Path, f.URLPrefix, "", 1)
	}

	p := fcgiPathInfo.FindStringSubmatch(urlPath)

	if len(p) < 2 {
		if strings.HasSuffix(r.URL.Path, "/") {
			// redirect to index.php
			scriptName = ""
			pathInfo = ""
			scriptFileName = filepath.Join(f.DocRoot, urlPath, "index.php")
		} else {
			// serve static file in php directory
			fn := filepath.Join(f.DocRoot, urlPath)
			http.ServeFile(w, r, fn)
			return
		}
	} else {
		scriptName = p[1]
		pathInfo = p[2]
		scriptFileName = filepath.Join(f.DocRoot, scriptName)
	}

	req := client.NewRequest(r)

	req.Params["PATH_INFO"] = pathInfo
	req.Params["SCRIPT_FILENAME"] = scriptFileName

	https := "off"
	scheme := "http"
	if r.TLS != nil {
		https = "on"
		scheme = "https"
	}

	req.Params["REQUEST_SCHEME"] = scheme
	req.Params["HTTPS"] = https

	host, port, _ := net.SplitHostPort(r.RemoteAddr)
	req.Params["REMOTE_ADDR"] = host
	req.Params["REMOTE_PORT"] = port

	host, port, err = net.SplitHostPort(r.Host)
	if err != nil {
		host = r.Host
		if scheme == "http" {
			port = "80"
		} else {
			port = "443"
		}
	}
	req.Params["SERVER_NAME"] = host
	req.Params["SERVER_PORT"] = port

	req.Params["SERVER_PROTOCOL"] = r.Proto

	for k, v := range r.Header {
		k = "HTTP_" + strings.ToUpper(strings.Replace(k, "-", "_", -1))
		if _, ok := req.Params[k]; ok == false {
			req.Params[k] = strings.Join(v, ";")
		}
	}

	resp, err := client.Do(req)
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusBadGateway)
		return
	}

	err = resp.WriteTo(w, os.Stderr)
	if err != nil {
		log.Println(err)
	}

	resp.Close()
}
Esempio n. 3
0
func TestClient_StdErr(t *testing.T) {

	// proxy implements Proxy interface
	type proxy struct {
		network string
		address string
	}

	// ServeHTTP implements http.Handler
	ServeHTTP := func(p *proxy, w http.ResponseWriter, r *http.Request) (errStr string) {
		conn, err := net.Dial(p.network, p.address)
		if err != nil {
			http.Error(w, "failed to connect to FastCGI application", http.StatusBadGateway)
			log.Printf("gofast: unable to connect to FastCGI application "+
				"(network=%#v, address=%#v, error=%#v)",
				p.network, p.address, err.Error())
			return
		}

		c := gofast.NewClient(conn, 0)
		req := c.NewRequest(nil)

		// Some required paramters with invalid values
		req.Params["REQUEST_METHOD"] = ""
		req.Params["SERVER_PROTOCOL"] = ""

		// handle the result
		resp, err := c.Do(req)
		if err != nil {
			http.Error(w, "failed to process request", http.StatusInternalServerError)
			log.Printf("gofast: unable to process request "+
				"(network=%#v, address=%#v, error=%#v)",
				p.network, p.address, err.Error())
			return
		}
		errBuffer := new(bytes.Buffer)
		resp.WriteTo(w, errBuffer)

		if errBuffer.Len() > 0 {
			errStr = errBuffer.String()
			log.Printf("gofast: error stream from application process "+
				"(network=%#v, address=%#v, error=%#v)",
				p.network, p.address, errStr)
			return
		}

		return
	}

	// create temporary socket in the testing folder
	dir, err := os.Getwd()
	if err != nil {
		t.Errorf("unexpected error: %#v", err.Error())
	}
	sock := dir + "/client.test.sock"

	// create temporary fcgi application server
	// that listens to the socket
	fn := func(w http.ResponseWriter, r *http.Request) {
		t.Logf("accessing FastCGI process")
		fmt.Fprintf(w, "hello world")
	}
	l, err := newApp("unix", sock, fn)
	if err != nil {
		t.Errorf("unexpected error: %#v", err.Error())
	}
	defer os.Remove(sock)
	defer l.Close()

	// deine a proxy that access the temp fcgi application server
	w := httptest.NewRecorder()

	// request the application server
	r, err := http.NewRequest("GET", "/add", nil)
	if err != nil {
		t.Errorf("unexpected error: %#v", err.Error())
	}

	p := &proxy{l.Addr().Network(), l.Addr().String()}
	if want, have := "cgi: no REQUEST_METHOD in environment", ServeHTTP(p, w, r); want != have {
		t.Errorf("expected %#v, got %#v", want, have)
	}

	// examine the result
	// FIXME: should show "internal server error"
	if want, have := "", w.Body.String(); want != have {
		t.Errorf("expected %#v, got %#v", want, have)
	}

}