all repos — captcha @ v1.0.0

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	"bytes"
 9	"net/http"
10	"path"
11	"strings"
12	"time"
13)
14
15type captchaHandler struct {
16	imgWidth  int
17	imgHeight int
18}
19
20// Server returns a handler that serves HTTP requests with image or
21// audio representations of captchas. Image dimensions are accepted as
22// arguments. The server decides which captcha to serve based on the last URL
23// path component: file name part must contain a captcha id, file extension —
24// its format (PNG or WAV).
25//
26// For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha
27// with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the
28// same captcha in audio format.
29//
30// To serve a captcha as a downloadable file, the URL must be constructed in
31// such a way as if the file to serve is in the "download" subdirectory:
32// "/download/LBm5vMjHDtdUfaWYXiQX.wav".
33//
34// To reload captcha (get a different solution for the same captcha id), append
35// "?reload=x" to URL, where x may be anything (for example, current time or a
36// random number to make browsers refetch an image instead of loading it from
37// cache).
38//
39// By default, the Server serves audio in English language. To serve audio
40// captcha in one of the other supported languages, append "lang" value, for
41// example, "?lang=ru".
42func Server(imgWidth, imgHeight int) http.Handler {
43	return &captchaHandler{imgWidth, imgHeight}
44}
45
46func (h *captchaHandler) serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool) error {
47	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
48	w.Header().Set("Pragma", "no-cache")
49	w.Header().Set("Expires", "0")
50
51	var content bytes.Buffer
52	switch ext {
53	case ".png":
54		w.Header().Set("Content-Type", "image/png")
55		WriteImage(&content, id, h.imgWidth, h.imgHeight)
56	case ".wav":
57		w.Header().Set("Content-Type", "audio/x-wav")
58		WriteAudio(&content, id, lang)
59	default:
60		return ErrNotFound
61	}
62
63	if download {
64		w.Header().Set("Content-Type", "application/octet-stream")
65	}
66	http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes()))
67	return nil
68}
69
70func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
71	dir, file := path.Split(r.URL.Path)
72	ext := path.Ext(file)
73	id := file[:len(file)-len(ext)]
74	if ext == "" || id == "" {
75		http.NotFound(w, r)
76		return
77	}
78	if r.FormValue("reload") != "" {
79		Reload(id)
80	}
81	lang := strings.ToLower(r.FormValue("lang"))
82	download := path.Base(dir) == "download"
83	if h.serve(w, r, id, ext, lang, download) == ErrNotFound {
84		http.NotFound(w, r)
85	}
86	// Ignore other errors.
87}