all repos — captcha @ cb56dd203fae15315b91e7265d5b8c73ca05218a

Go package captcha implements generation and verification of image and audio CAPTCHAs.

server.go (view raw)

 1package captcha
 2
 3import (
 4	"http"
 5	"os"
 6	"path"
 7	"strconv"
 8	"strings"
 9)
10
11type captchaHandler struct {
12	imgWidth  int
13	imgHeight int
14}
15
16// Server returns a handler that serves HTTP requests with image or
17// audio representations of captchas. Image dimensions are accepted as
18// arguments. The server decides which captcha to serve based on the last URL
19// path component: file name part must contain a captcha id, file extension —
20// its format (PNG or WAV).
21//
22// For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha
23// with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the
24// same captcha in audio format.
25//
26// To serve a captcha as a downloadable file, the URL must be constructed in
27// such a way as if the file to serve is in the "download" subdirectory:
28// "/download/LBm5vMjHDtdUfaWYXiQX.wav".
29//
30// To reload captcha (get a different solution for the same captcha id), append
31// "?reload=x" to URL, where x may be anything (for example, current time or a
32// random number to make browsers refetch an image instead of loading it from
33// cache).
34//
35// By default, the Server serves audio in English language. To serve audio
36// captcha in one of the other supported languages, append "lang" value, for
37// example, "?lang=ru".
38func Server(imgWidth, imgHeight int) http.Handler { 
39	return &captchaHandler{imgWidth, imgHeight}
40}
41
42func (h *captchaHandler) serve(w http.ResponseWriter, id, ext string, lang string, download bool) os.Error {
43	if download {
44		w.Header().Set("Content-Type", "application/octet-stream")
45	}
46	switch ext {
47	case ".png":
48		if !download {
49			w.Header().Set("Content-Type", "image/png")
50		}
51		return WriteImage(w, id, h.imgWidth, h.imgHeight)
52	case ".wav":
53		//XXX(dchest) Workaround for Chrome: it wants content-length,
54		//or else will start playing NOT from the beginning.
55		//Filed issue: http://code.google.com/p/chromium/issues/detail?id=80565
56		d := globalStore.Get(id, false)
57		if d == nil {
58			return ErrNotFound
59		}
60		a := NewAudio(d, lang)
61		if !download {
62			w.Header().Set("Content-Type", "audio/x-wav")
63		}
64		w.Header().Set("Content-Length", strconv.Itoa(a.EncodedLen()))
65		_, err := a.WriteTo(w)
66		return err
67	}
68	return ErrNotFound
69}
70
71func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
72	dir, file := path.Split(r.URL.Path)
73	ext := path.Ext(file)
74	id := file[:len(file)-len(ext)]
75	if ext == "" || id == "" {
76		http.NotFound(w, r)
77		return
78	}
79	if r.FormValue("reload") != "" {
80		Reload(id)
81	}
82	lang := strings.ToLower(r.FormValue("lang"))
83	download := path.Base(dir) == "download"
84	if h.serve(w, id, ext, lang, download) == ErrNotFound {
85		http.NotFound(w, r)
86	}
87	// Ignore other errors.
88}