go.talks/pkg/socket: sanitize message bodies

This change prevents a socket connection from going down when a program
emits garbage, as the JSON encoder chokes on invalid UTF-8.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/8589051
diff --git a/pkg/socket/socket.go b/pkg/socket/socket.go
index f58db5e..13c6e8e 100644
--- a/pkg/socket/socket.go
+++ b/pkg/socket/socket.go
@@ -14,6 +14,7 @@
 package socket
 
 import (
+	"bytes"
 	"encoding/json"
 	"io"
 	"io/ioutil"
@@ -23,6 +24,7 @@
 	"path/filepath"
 	"runtime"
 	"strconv"
+	"unicode/utf8"
 
 	"code.google.com/p/go.net/websocket"
 )
@@ -213,10 +215,24 @@
 }
 
 func (w *messageWriter) Write(b []byte) (n int, err error) {
-	w.out <- &Message{Id: w.id, Kind: w.kind, Body: string(b)}
+	w.out <- &Message{Id: w.id, Kind: w.kind, Body: safeString(b)}
 	return len(b), nil
 }
 
+// safeString returns b as a valid UTF-8 string.
+func safeString(b []byte) string {
+	if utf8.Valid(b) {
+		return string(b)
+	}
+	var buf bytes.Buffer
+	for len(b) > 0 {
+		r, size := utf8.DecodeRune(b)
+		b = b[size:]
+		buf.WriteRune(r)
+	}
+	return buf.String()
+}
+
 // limiter returns a channel that wraps dest. Messages sent to the channel are
 // sent to dest. After msgLimit Messages have been passed on, a "kill" Message
 // is sent to the kill channel, and only "end" messages are passed.