playground: allow CORS requests on /compile and /vet endpoints

This is needed by the new blog frontend (and would be helpful for
others who wish to embed runnable playground snippets using only JS).

Change-Id: I8e1dcb4022ec15222e8ad3114b92e85d896f641e
Reviewed-by: Brad Fitzpatrick <>
diff --git a/sandbox.go b/sandbox.go
index ce020ec..36d2f28 100644
--- a/sandbox.go
+++ b/sandbox.go
@@ -55,8 +55,15 @@
 // from the "body" form parameter or from the HTTP request body.
 // If there is no cached *response for the combination of cachePrefix and request.Body,
 // handler calls cmdFunc and in case of a nil error, stores the value of *response in the cache.
+// The handler returned supports Cross-Origin Resource Sharing (CORS) from any domain.
 func (s *server) commandHandler(cachePrefix string, cmdFunc func(*request) (*response, error)) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Access-Control-Allow-Origin", "*")
+		if r.Method == "OPTIONS" {
+			// This is likely a pre-flight CORS request.
+			return
+		}
 		var req request
 		// Until programs that depend on
 		// are updated to always send JSON, this check is in place.
diff --git a/server_test.go b/server_test.go
index a0f00eb..0c17407 100644
--- a/server_test.go
+++ b/server_test.go
@@ -175,7 +175,7 @@
 		reqBody    []byte
 		respBody   []byte
-		{"OPTIONS request", http.MethodOptions, http.StatusBadRequest, nil, nil},
+		{"OPTIONS request", http.MethodOptions, http.StatusOK, nil, nil},
 		{"GET request", http.MethodGet, http.StatusBadRequest, nil, nil},
 		{"Empty POST", http.MethodPost, http.StatusBadRequest, nil, nil},
 		{"Failed cmdFunc", http.MethodPost, http.StatusInternalServerError, []byte(`{"Body":"fail"}`), nil},
@@ -196,6 +196,10 @@
 		w := httptest.NewRecorder()
 		testHandler(w, req)
 		resp := w.Result()
+		corsHeader := "Access-Control-Allow-Origin"
+		if got, want := resp.Header.Get(corsHeader), "*"; got != want {
+			t.Errorf("%s: %q header: got %q; want %q", tc.desc, corsHeader, got, want)
+		}
 		if got, want := resp.StatusCode, tc.statusCode; got != want {
 			t.Errorf("%s: got unexpected status code %d; want %d", tc.desc, got, want)