server.go 2.2 KB

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