1 // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Command server is a test server for the Autobahn WebSockets Test Suite.
17 "github.com/gorilla/websocket"
20 var upgrader = websocket.Upgrader{
22 WriteBufferSize: 4096,
23 EnableCompression: true,
24 CheckOrigin: func(r *http.Request) bool {
29 // echoCopy echoes messages from the client using io.Copy.
30 func echoCopy(w http.ResponseWriter, r *http.Request, writerOnly bool) {
31 conn, err := upgrader.Upgrade(w, r, nil)
33 log.Println("Upgrade:", err)
38 mt, r, err := conn.NextReader()
41 log.Println("NextReader:", err)
45 if mt == websocket.TextMessage {
48 w, err := conn.NextWriter(mt)
50 log.Println("NextWriter:", err)
53 if mt == websocket.TextMessage {
57 _, err = io.Copy(struct{ io.Writer }{w}, r)
59 _, err = io.Copy(w, r)
62 if err == errInvalidUTF8 {
63 conn.WriteControl(websocket.CloseMessage,
64 websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
67 log.Println("Copy:", err)
72 log.Println("Close:", err)
78 func echoCopyWriterOnly(w http.ResponseWriter, r *http.Request) {
82 func echoCopyFull(w http.ResponseWriter, r *http.Request) {
86 // echoReadAll echoes messages from the client by reading the entire message
87 // with ioutil.ReadAll.
88 func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage, writePrepared bool) {
89 conn, err := upgrader.Upgrade(w, r, nil)
91 log.Println("Upgrade:", err)
96 mt, b, err := conn.ReadMessage()
99 log.Println("NextReader:", err)
103 if mt == websocket.TextMessage {
105 conn.WriteControl(websocket.CloseMessage,
106 websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
108 log.Println("ReadAll: invalid utf8")
113 err = conn.WriteMessage(mt, b)
115 log.Println("WriteMessage:", err)
118 pm, err := websocket.NewPreparedMessage(mt, b)
120 log.Println("NewPreparedMessage:", err)
123 err = conn.WritePreparedMessage(pm)
125 log.Println("WritePreparedMessage:", err)
129 w, err := conn.NextWriter(mt)
131 log.Println("NextWriter:", err)
134 if _, err := w.Write(b); err != nil {
135 log.Println("Writer:", err)
138 if err := w.Close(); err != nil {
139 log.Println("Close:", err)
146 func echoReadAllWriter(w http.ResponseWriter, r *http.Request) {
147 echoReadAll(w, r, false, false)
150 func echoReadAllWriteMessage(w http.ResponseWriter, r *http.Request) {
151 echoReadAll(w, r, true, false)
154 func echoReadAllWritePreparedMessage(w http.ResponseWriter, r *http.Request) {
155 echoReadAll(w, r, true, true)
158 func serveHome(w http.ResponseWriter, r *http.Request) {
159 if r.URL.Path != "/" {
160 http.Error(w, "Not found.", http.StatusNotFound)
163 if r.Method != "GET" {
164 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
167 w.Header().Set("Content-Type", "text/html; charset=utf-8")
168 io.WriteString(w, "<html><body>Echo Server</body></html>")
171 var addr = flag.String("addr", ":9000", "http service address")
175 http.HandleFunc("/", serveHome)
176 http.HandleFunc("/c", echoCopyWriterOnly)
177 http.HandleFunc("/f", echoCopyFull)
178 http.HandleFunc("/r", echoReadAllWriter)
179 http.HandleFunc("/m", echoReadAllWriteMessage)
180 http.HandleFunc("/p", echoReadAllWritePreparedMessage)
181 err := http.ListenAndServe(*addr, nil)
183 log.Fatal("ListenAndServe: ", err)
187 type validator struct {
193 var errInvalidUTF8 = errors.New("invalid utf8")
195 func (r *validator) Read(p []byte) (int, error) {
196 n, err := r.r.Read(p)
199 for _, b := range p[:n] {
200 state, x = decode(state, x, b)
201 if state == utf8Reject {
207 if state == utf8Reject || (err == io.EOF && state != utf8Accept) {
208 return n, errInvalidUTF8
213 // UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
215 // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
217 // Permission is hereby granted, free of charge, to any person obtaining a copy
218 // of this software and associated documentation files (the "Software"), to
219 // deal in the Software without restriction, including without limitation the
220 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
221 // sell copies of the Software, and to permit persons to whom the Software is
222 // furnished to do so, subject to the following conditions:
224 // The above copyright notice and this permission notice shall be included in
225 // all copies or substantial portions of the Software.
227 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
228 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
229 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
230 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
231 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
232 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
234 var utf8d = [...]byte{
235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
238 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
239 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
240 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
241 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
242 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
243 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
244 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
245 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
246 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
247 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
248 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8
256 func decode(state int, x rune, b byte) (int, rune) {
258 if state != utf8Accept {
259 x = rune(b&0x3f) | (x << 6)
261 x = rune((0xff >> t) & b)
263 state = int(utf8d[256+state*16+int(t)])