123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- // Copyright 2011 Dmitry Chestnykh. All rights reserved.
- // Use of this source code is governed by a MIT-style
- // license that can be found in the LICENSE file.
- package captcha
- import (
- "bytes"
- "net/http"
- "path"
- "strings"
- "time"
- )
- type captchaHandler struct {
- imgWidth int
- imgHeight int
- }
- // Server returns a handler that serves HTTP requests with image or
- // audio representations of captchas. Image dimensions are accepted as
- // arguments. The server decides which captcha to serve based on the last URL
- // path component: file name part must contain a captcha id, file extension —
- // its format (PNG or WAV).
- //
- // For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha
- // with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the
- // same captcha in audio format.
- //
- // To serve a captcha as a downloadable file, the URL must be constructed in
- // such a way as if the file to serve is in the "download" subdirectory:
- // "/download/LBm5vMjHDtdUfaWYXiQX.wav".
- //
- // To reload captcha (get a different solution for the same captcha id), append
- // "?reload=x" to URL, where x may be anything (for example, current time or a
- // random number to make browsers refetch an image instead of loading it from
- // cache).
- //
- // By default, the Server serves audio in English language. To serve audio
- // captcha in one of the other supported languages, append "lang" value, for
- // example, "?lang=ru".
- func Server(imgWidth, imgHeight int) http.Handler {
- return &captchaHandler{imgWidth, imgHeight}
- }
- func (h *captchaHandler) serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool) error {
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- w.Header().Set("Pragma", "no-cache")
- w.Header().Set("Expires", "0")
- var content bytes.Buffer
- switch ext {
- case ".png":
- w.Header().Set("Content-Type", "image/png")
- WriteImage(&content, id, h.imgWidth, h.imgHeight)
- case ".wav":
- w.Header().Set("Content-Type", "audio/x-wav")
- WriteAudio(&content, id, lang)
- default:
- return ErrNotFound
- }
- if download {
- w.Header().Set("Content-Type", "application/octet-stream")
- }
- http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes()))
- return nil
- }
- func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- dir, file := path.Split(r.URL.Path)
- ext := path.Ext(file)
- id := file[:len(file)-len(ext)]
- if ext == "" || id == "" {
- http.NotFound(w, r)
- return
- }
- if r.FormValue("reload") != "" {
- Reload(id)
- }
- lang := strings.ToLower(r.FormValue("lang"))
- download := path.Base(dir) == "download"
- if h.serve(w, r, id, ext, lang, download) == ErrNotFound {
- http.NotFound(w, r)
- }
- // Ignore other errors.
- }
|