1 // Copyright 2013 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.
5 // Package playground registers HTTP handlers at "/compile" and "/share" that
6 // proxy requests to the golang.org playground service.
7 // This package may be used unaltered on App Engine Standard with Go 1.11+ runtime.
8 package playground // import "golang.org/x/tools/playground"
21 "golang.org/x/tools/godoc/golangorgenv"
24 const baseURL = "https://play.golang.org"
27 http.HandleFunc("/compile", bounce)
28 http.HandleFunc("/share", bounce)
31 func bounce(w http.ResponseWriter, r *http.Request) {
32 b := new(bytes.Buffer)
33 if err := passThru(b, r); os.IsPermission(err) {
34 http.Error(w, "403 Forbidden", http.StatusForbidden)
37 } else if err != nil {
38 http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
45 func passThru(w io.Writer, req *http.Request) error {
46 if req.URL.Path == "/share" && googleCN(req) {
47 return os.ErrPermission
49 defer req.Body.Close()
50 url := baseURL + req.URL.Path
51 ctx, cancel := context.WithTimeout(req.Context(), 60*time.Second)
53 r, err := post(ctx, url, req.Header.Get("Content-Type"), req.Body)
55 return fmt.Errorf("making POST request: %v", err)
58 if _, err := io.Copy(w, r.Body); err != nil {
59 return fmt.Errorf("copying response Body: %v", err)
64 func post(ctx context.Context, url, contentType string, body io.Reader) (*http.Response, error) {
65 req, err := http.NewRequest(http.MethodPost, url, body)
67 return nil, fmt.Errorf("http.NewRequest: %v", err)
69 req.Header.Set("Content-Type", contentType)
70 return http.DefaultClient.Do(req.WithContext(ctx))
73 // googleCN reports whether request r is considered
74 // to be served from golang.google.cn.
75 func googleCN(r *http.Request) bool {
76 if r.FormValue("googlecn") != "" {
79 if strings.HasSuffix(r.Host, ".cn") {
82 if !golangorgenv.CheckCountry() {
85 switch r.Header.Get("X-Appengine-Country") {