|
@@ -45,11 +45,8 @@ import (
|
|
|
"bytes"
|
|
"bytes"
|
|
|
"crypto/rand"
|
|
"crypto/rand"
|
|
|
"github.com/dchest/uniuri"
|
|
"github.com/dchest/uniuri"
|
|
|
- "http"
|
|
|
|
|
"io"
|
|
"io"
|
|
|
"os"
|
|
"os"
|
|
|
- "path"
|
|
|
|
|
- "strconv"
|
|
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
const (
|
|
@@ -178,72 +175,3 @@ func VerifyString(id string, digits string) bool {
|
|
|
func Collect() {
|
|
func Collect() {
|
|
|
go globalStore.Collect()
|
|
go globalStore.Collect()
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-type captchaHandler struct {
|
|
|
|
|
- imgWidth int
|
|
|
|
|
- imgHeight int
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// Server returns a handler that serves HTTP requests with image or
|
|
|
|
|
-// audio representations of captchas. Image dimensions are accepted as
|
|
|
|
|
-// arguments. The server decides which captcha to serve based on the last URL
|
|
|
|
|
-// path component: file name part must contain a captcha id, file extension —
|
|
|
|
|
-// its format (PNG or WAV).
|
|
|
|
|
-//
|
|
|
|
|
-// For example, for file name "B9QTvDV1RXbVJ3Ac.png" it serves an image captcha
|
|
|
|
|
-// with id "B9QTvDV1RXbVJ3Ac", and for "B9QTvDV1RXbVJ3Ac.wav" it serves the
|
|
|
|
|
-// same captcha in audio format.
|
|
|
|
|
-//
|
|
|
|
|
-// To serve an audio captcha as downloadable file, append "?get" to URL.
|
|
|
|
|
-//
|
|
|
|
|
-// To reload captcha (get a different solution for the same captcha id), append
|
|
|
|
|
-// "?reload=x" to URL, where x may be anything (for example, current time or a
|
|
|
|
|
-// random number to make browsers refetch an image instead of loading it from
|
|
|
|
|
-// cache).
|
|
|
|
|
-func Server(w, h int) http.Handler { return &captchaHandler{w, h} }
|
|
|
|
|
-
|
|
|
|
|
-func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
- _, file := path.Split(r.URL.Path)
|
|
|
|
|
- ext := path.Ext(file)
|
|
|
|
|
- id := file[:len(file)-len(ext)]
|
|
|
|
|
- if ext == "" || id == "" {
|
|
|
|
|
- http.NotFound(w, r)
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- if r.FormValue("reload") != "" {
|
|
|
|
|
- Reload(id)
|
|
|
|
|
- }
|
|
|
|
|
- var err os.Error
|
|
|
|
|
- switch ext {
|
|
|
|
|
- case ".png":
|
|
|
|
|
- w.Header().Set("Content-Type", "image/png")
|
|
|
|
|
- err = WriteImage(w, id, h.imgWidth, h.imgHeight)
|
|
|
|
|
- case ".wav":
|
|
|
|
|
- if r.URL.RawQuery == "get" {
|
|
|
|
|
- w.Header().Set("Content-Type", "application/octet-stream")
|
|
|
|
|
- } else {
|
|
|
|
|
- w.Header().Set("Content-Type", "audio/x-wav")
|
|
|
|
|
- }
|
|
|
|
|
- //err = WriteAudio(w, id)
|
|
|
|
|
- //XXX(dchest) Workaround for Chrome: it wants content-length,
|
|
|
|
|
- //or else will start playing NOT from the beginning.
|
|
|
|
|
- //Filed issue: http://code.google.com/p/chromium/issues/detail?id=80565
|
|
|
|
|
- d := globalStore.Get(id, false)
|
|
|
|
|
- if d == nil {
|
|
|
|
|
- err = ErrNotFound
|
|
|
|
|
- } else {
|
|
|
|
|
- a := NewAudio(d)
|
|
|
|
|
- w.Header().Set("Content-Length", strconv.Itoa(a.EncodedLen()))
|
|
|
|
|
- _, err = a.WriteTo(w)
|
|
|
|
|
- }
|
|
|
|
|
- default:
|
|
|
|
|
- err = ErrNotFound
|
|
|
|
|
- }
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- if err == ErrNotFound {
|
|
|
|
|
- http.NotFound(w, r)
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- http.Error(w, "error serving captcha", http.StatusInternalServerError)
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|