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