in sandbox.go [95:167]
func (s *server) commandHandler(cachePrefix string, cmdFunc func(context.Context, *request) (*response, error)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cachePrefix := cachePrefix // so we can modify it below
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 golang.org/x/tools/godoc/static/playground.js
// are updated to always send JSON, this check is in place.
if b := r.FormValue("body"); b != "" {
req.Body = b
req.WithVet, _ = strconv.ParseBool(r.FormValue("withVet"))
} else if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
s.log.Errorf("error decoding request: %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
if req.WithVet {
cachePrefix += "_vet" // "prog" -> "prog_vet"
}
resp := &response{}
key := cacheKey(cachePrefix, req.Body)
if err := s.cache.Get(key, resp); err != nil {
if !errors.Is(err, memcache.ErrCacheMiss) {
s.log.Errorf("s.cache.Get(%q, &response): %v", key, err)
}
resp, err = cmdFunc(r.Context(), &req)
if err != nil {
s.log.Errorf("cmdFunc error: %v", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
if strings.Contains(resp.Errors, goBuildTimeoutError) || strings.Contains(resp.Errors, runTimeoutError) {
// TODO(golang.org/issue/38576) - This should be a http.StatusBadRequest,
// but the UI requires a 200 to parse the response. It's difficult to know
// if we've timed out because of an error in the code snippet, or instability
// on the playground itself. Either way, we should try to show the user the
// partial output of their program.
s.writeJSONResponse(w, resp, http.StatusOK)
return
}
for _, e := range internalErrors {
if strings.Contains(resp.Errors, e) {
s.log.Errorf("cmdFunc compilation error: %q", resp.Errors)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
}
for _, el := range resp.Events {
if el.Kind != "stderr" {
continue
}
for _, e := range internalErrors {
if strings.Contains(el.Message, e) {
s.log.Errorf("cmdFunc runtime error: %q", el.Message)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
}
}
if err := s.cache.Set(key, resp); err != nil {
s.log.Errorf("cache.Set(%q, resp): %v", key, err)
}
}
s.writeJSONResponse(w, resp, http.StatusOK)
}
}