Browse Source

Add Audio.EncodedLen. Workaround for Chrome WAV bug.

Dmitry Chestnykh 14 years ago
parent
commit
8a2b5ae5df
2 changed files with 26 additions and 4 deletions
  1. 5 0
      audio.go
  2. 21 4
      captcha.go

+ 5 - 0
audio.go

@@ -91,6 +91,11 @@ func (a *Audio) WriteTo(w io.Writer) (n int64, err os.Error) {
 	return
 	return
 }
 }
 
 
+// EncodedLen returns the length of WAV-encoded audio captcha.
+func (a *Audio) EncodedLen() int {
+	return len(waveHeader) + 4 + a.body.Len()
+}
+
 // mixSound mixes src into dst. Dst must have length equal to or greater than
 // mixSound mixes src into dst. Dst must have length equal to or greater than
 // src length.
 // src length.
 func mixSound(dst, src []byte) {
 func mixSound(dst, src []byte) {

+ 21 - 4
captcha.go

@@ -8,6 +8,7 @@ import (
 	"io"
 	"io"
 	"os"
 	"os"
 	"path"
 	"path"
+	"strconv"
 )
 )
 
 
 const (
 const (
@@ -16,7 +17,7 @@ const (
 	// The number of captchas created that triggers garbage collection.
 	// The number of captchas created that triggers garbage collection.
 	StdCollectNum = 100
 	StdCollectNum = 100
 	// Expiration time of captchas.
 	// Expiration time of captchas.
-	StdExpiration = 2 * 60 // 2 minutes
+	StdExpiration = 10 * 60 // 10 minutes
 
 
 )
 )
 
 
@@ -135,7 +136,7 @@ type captchaHandler struct {
 	imgHeight int
 	imgHeight int
 }
 }
 
 
-// CaptchaServer returns a handler that serves HTTP requests with image or
+// Server returns a handler that serves HTTP requests with image or
 // audio representations of captchas. Image dimensions are accepted as
 // audio representations of captchas. Image dimensions are accepted as
 // arguments. The server decides which captcha to serve based on the last URL
 // 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 —
 // path component: file name part must contain a captcha id, file extension —
@@ -144,6 +145,8 @@ type captchaHandler struct {
 // For example, for file name "B9QTvDV1RXbVJ3Ac.png" it serves an image captcha
 // For example, for file name "B9QTvDV1RXbVJ3Ac.png" it serves an image captcha
 // with id "B9QTvDV1RXbVJ3Ac", and for "B9QTvDV1RXbVJ3Ac.wav" it serves the
 // with id "B9QTvDV1RXbVJ3Ac", and for "B9QTvDV1RXbVJ3Ac.wav" it serves the
 // same captcha in audio format.
 // same captcha in audio format.
+//
+// To serve an audio captcha as downloadable file, append "?get" to URL.
 func Server(w, h int) http.Handler { return &captchaHandler{w, h} }
 func Server(w, h int) http.Handler { return &captchaHandler{w, h} }
 
 
 func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -160,8 +163,22 @@ func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Content-Type", "image/png")
 		w.Header().Set("Content-Type", "image/png")
 		err = WriteImage(w, id, h.imgWidth, h.imgHeight)
 		err = WriteImage(w, id, h.imgWidth, h.imgHeight)
 	case ".wav", ".WAV":
 	case ".wav", ".WAV":
-		w.Header().Set("Content-Type", "audio/x-wav")
-		err = WriteAudio(w, id)
+		if r.URL.RawQuery == "get" {
+			w.Header().Set("Content-Type", "application/octet-stream")
+		} else {
+			w.Header().Set("Content-Type", "audio/x-wav")
+		}
+		//err = WriteAudio(buf, id)
+		//XXX(dchest) Workaround for Chrome: it wants content-length,
+		//or else will start playing NOT from the beginning.
+		d := globalStore.getDigits(id)
+		if d == nil {
+			err = ErrNotFound
+		} else {
+			a := NewAudio(d)
+			w.Header().Set("Content-Length", strconv.Itoa(a.EncodedLen()))
+			_, err = a.WriteTo(w)
+		}
 	default:
 	default:
 		err = ErrNotFound
 		err = ErrNotFound
 	}
 	}