diff --git a/doc/appengine/app.yaml b/doc/appengine/app.yaml new file mode 100644 index 00000000..bcf370c8 --- /dev/null +++ b/doc/appengine/app.yaml @@ -0,0 +1,9 @@ +application: crashpad-home +version: 1 +runtime: go +api_version: go1 + +handlers: +- url: /.* + script: _go_app + secure: always diff --git a/doc/appengine/main.go b/doc/appengine/main.go new file mode 100644 index 00000000..261440d4 --- /dev/null +++ b/doc/appengine/main.go @@ -0,0 +1,122 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package crashpad mirrors crashpad documentation from Chromium’s git repo. +package crashpad + +import ( + "encoding/base64" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "path" + "strings" + "time" + + "google.golang.org/appengine" + "google.golang.org/appengine/memcache" + "google.golang.org/appengine/urlfetch" +) + +const baseURL = "https://chromium.googlesource.com/crashpad/crashpad/+/doc/doc/generated/?format=TEXT" + +func init() { + http.HandleFunc("/", handler) +} + +func handler(w http.ResponseWriter, r *http.Request) { + ctx := appengine.NewContext(r) + client := urlfetch.Client(ctx) + + // Don’t show dotfiles. + if strings.HasPrefix(path.Base(r.URL.Path), ".") { + http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + return + } + + u, err := url.Parse(baseURL) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + u.Path = path.Join(u.Path, r.URL.Path) + urlStr := u.String() + + item, err := memcache.Get(ctx, urlStr) + if err == memcache.ErrCacheMiss { + resp, err := client.Get(urlStr) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + w.WriteHeader(resp.StatusCode) + for k, v := range w.Header() { + w.Header()[k] = v + } + io.Copy(w, resp.Body) + return + } + + // Redirect directories to their index pages (/doc/ -> /doc/index.html). + if resp.Header.Get("X-Gitiles-Object-Type") == "tree" { + http.Redirect(w, r, path.Join(r.URL.Path, "/index.html"), http.StatusFound) + return + } + + decoder := base64.NewDecoder(base64.StdEncoding, resp.Body) + b, err := ioutil.ReadAll(decoder) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + item = &memcache.Item{ + Key: urlStr, + Value: b, + Expiration: 1 * time.Hour, + } + if err := memcache.Set(ctx, item); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", contentType(path.Base(u.Path))) + fmt.Fprintf(w, "%s", item.Value) +} + +// contentType returns the appropriate content type header for file. +func contentType(file string) string { + contentTypes := map[string]string{ + ".html": "text/html; charset=UTF-8", + ".css": "text/css; charset=UTF-8", + ".js": "text/javascript; charset=UTF-8", + ".png": "image/png", + ".ico": "image/x-icon", + } + for suffix, typ := range contentTypes { + if strings.HasSuffix(file, suffix) { + return typ + } + } + return "text/plain; charset=UTF-8" +} diff --git a/doc/favicon.ico b/doc/favicon.ico new file mode 100644 index 00000000..23c553a2 Binary files /dev/null and b/doc/favicon.ico differ diff --git a/doc/support/generate.sh b/doc/support/generate.sh index f5785c64..f4410aee 100755 --- a/doc/support/generate.sh +++ b/doc/support/generate.sh @@ -43,10 +43,16 @@ done # Move doc/index.html to index.html, adjusting relative paths to other files in # doc. +base_url=https://crashpad-home.appspot.com/ ${sed_ext} -e 's%%%g' \ + -e 's%%%g' \ + -e 's% "${output_dir}/index.html" rm "${output_dir}/doc/index.html" +# Ensure a favicon exists at the root since the browser will always request it. +cp doc/favicon.ico "${output_dir}/" + # Create man/index.html cd "${output_dir}/man" cat > index.html << __EOF__