Skip to content

Commit 5ac9766

Browse files
committed
playground: add a version endpoint
Add a /version handler to serve information about the playground Go version. Also consolidate writing JSON responses into a common helper. Change-Id: I1bb3de4c23320eb58306c93a51dbe9ae5176382d Reviewed-on: https://go-review.googlesource.com/c/playground/+/365854 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
1 parent 6c55170 commit 5ac9766

File tree

6 files changed

+74
-20
lines changed

6 files changed

+74
-20
lines changed

fmt.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type fmtResponse struct {
2020
Error string
2121
}
2222

23-
func handleFmt(w http.ResponseWriter, r *http.Request) {
23+
func (s *server) handleFmt(w http.ResponseWriter, r *http.Request) {
2424
w.Header().Set("Access-Control-Allow-Origin", "*")
2525
if r.Method == "OPTIONS" {
2626
// This is likely a pre-flight CORS request.
@@ -69,7 +69,7 @@ func handleFmt(w http.ResponseWriter, r *http.Request) {
6969
}
7070
}
7171

72-
json.NewEncoder(w).Encode(fmtResponse{Body: string(fs.Format())})
72+
s.writeJSONResponse(w, fmtResponse{Body: string(fs.Format())}, http.StatusOK)
7373
}
7474

7575
func formatGoMod(file string, data []byte) ([]byte, error) {

fmt_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import (
1414
)
1515

1616
func TestHandleFmt(t *testing.T) {
17+
s, err := newServer(testingOptions(t))
18+
if err != nil {
19+
t.Fatalf("newServer(testingOptions(t)): %v", err)
20+
}
21+
1722
for _, tt := range []struct {
1823
name string
1924
method string
@@ -125,7 +130,7 @@ func TestHandleFmt(t *testing.T) {
125130
}
126131
req := httptest.NewRequest("POST", "/fmt", strings.NewReader(form.Encode()))
127132
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
128-
handleFmt(rec, req)
133+
s.handleFmt(rec, req)
129134
resp := rec.Result()
130135
if resp.StatusCode != 200 {
131136
t.Fatalf("code = %v", resp.Status)

sandbox.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func (s *server) commandHandler(cachePrefix string, cmdFunc func(context.Context
135135
// if we've timed out because of an error in the code snippet, or instability
136136
// on the playground itself. Either way, we should try to show the user the
137137
// partial output of their program.
138-
s.writeResponse(w, resp, http.StatusOK)
138+
s.writeJSONResponse(w, resp, http.StatusOK)
139139
return
140140
}
141141
for _, e := range internalErrors {
@@ -162,21 +162,7 @@ func (s *server) commandHandler(cachePrefix string, cmdFunc func(context.Context
162162
}
163163
}
164164

165-
s.writeResponse(w, resp, http.StatusOK)
166-
}
167-
}
168-
169-
func (s *server) writeResponse(w http.ResponseWriter, resp *response, status int) {
170-
var buf bytes.Buffer
171-
if err := json.NewEncoder(&buf).Encode(resp); err != nil {
172-
s.log.Errorf("error encoding response: %v", err)
173-
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
174-
return
175-
}
176-
w.WriteHeader(status)
177-
if _, err := io.Copy(w, &buf); err != nil {
178-
s.log.Errorf("io.Copy(w, &buf): %v", err)
179-
return
165+
s.writeJSONResponse(w, resp, http.StatusOK)
180166
}
181167
}
182168

server.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
package main
66

77
import (
8+
"bytes"
9+
"encoding/json"
810
"fmt"
11+
"io"
912
"net/http"
1013
"strings"
1114
"time"
@@ -47,7 +50,8 @@ func newServer(options ...func(s *server) error) (*server, error) {
4750

4851
func (s *server) init() {
4952
s.mux.HandleFunc("/", s.handleEdit)
50-
s.mux.HandleFunc("/fmt", handleFmt)
53+
s.mux.HandleFunc("/fmt", s.handleFmt)
54+
s.mux.HandleFunc("/version", s.handleVersion)
5155
s.mux.HandleFunc("/vet", s.commandHandler("vet", vetCheck))
5256
s.mux.HandleFunc("/compile", s.commandHandler("prog", compileAndRun))
5357
s.mux.HandleFunc("/share", s.handleShare)
@@ -90,3 +94,20 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
9094
}
9195
s.mux.ServeHTTP(w, r)
9296
}
97+
98+
// writeJSONResponse JSON-encodes resp and writes to w with the given HTTP
99+
// status.
100+
func (s *server) writeJSONResponse(w http.ResponseWriter, resp interface{}, status int) {
101+
w.Header().Set("Content-Type", "application/json")
102+
var buf bytes.Buffer
103+
if err := json.NewEncoder(&buf).Encode(resp); err != nil {
104+
s.log.Errorf("error encoding response: %v", err)
105+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
106+
return
107+
}
108+
w.WriteHeader(status)
109+
if _, err := io.Copy(w, &buf); err != nil {
110+
s.log.Errorf("io.Copy(w, &buf): %v", err)
111+
return
112+
}
113+
}

server_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"net/http"
1414
"net/http/httptest"
1515
"os"
16+
"runtime"
1617
"sync"
1718
"testing"
1819
"time"
@@ -133,6 +134,8 @@ func TestServer(t *testing.T) {
133134
{"HTTP example", http.MethodGet, "https://play.golang.org/doc/play/http.txt", http.StatusOK, nil, []byte("net/http")},
134135
// Gotip examples should not be available on the non-tip playground.
135136
{"Gotip example", http.MethodGet, "https://play.golang.org/doc/play/min.gotip.txt", http.StatusNotFound, nil, nil},
137+
138+
{"Versions json", http.MethodGet, "https://play.golang.org/version", http.StatusOK, nil, []byte(runtime.Version())},
136139
}
137140

138141
for _, tc := range testCases {

version.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2021 The Go 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.
4+
5+
package main
6+
7+
import (
8+
"fmt"
9+
"go/build"
10+
"net/http"
11+
"runtime"
12+
)
13+
14+
func (s *server) handleVersion(w http.ResponseWriter, req *http.Request) {
15+
w.Header().Set("Access-Control-Allow-Origin", "*")
16+
17+
tag := build.Default.ReleaseTags[len(build.Default.ReleaseTags)-1]
18+
var maj, min int
19+
if _, err := fmt.Sscanf(tag, "go%d.%d", &maj, &min); err != nil {
20+
code := http.StatusInternalServerError
21+
http.Error(w, http.StatusText(code), code)
22+
return
23+
}
24+
25+
version := struct {
26+
Version, Release, Name string
27+
}{
28+
Version: runtime.Version(),
29+
Release: tag,
30+
}
31+
32+
if s.gotip {
33+
version.Name = "Go dev branch"
34+
} else {
35+
version.Name = fmt.Sprintf("Go %d.%d", maj, min)
36+
}
37+
38+
s.writeJSONResponse(w, version, http.StatusOK)
39+
}

0 commit comments

Comments
 (0)