all repos — captcha @ 6a5989d72f51dc85d9d6e2c6f0ee79cf675a3cfd

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

server.go (view raw)

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