// mainHandler tracks how many times each user has visited this page. func mainHandler(w http.ResponseWriter, r *http.Request) *appError { if r.URL.Path != "/" { http.NotFound(w, r) return nil } ctx := appengine.NewContext(r) u := user.Current(ctx) if u == nil { login, err := user.LoginURL(ctx, r.URL.String()) if err != nil { return &appError{err, "Error finding login URL", http.StatusInternalServerError} } http.Redirect(w, r, login, http.StatusFound) return nil } logoutURL, err := user.LogoutURL(ctx, "/") if err != nil { return &appError{err, "Error finding logout URL", http.StatusInternalServerError} } // Display hello page. tbl := client.Open(tableName) rmw := bigtable.NewReadModifyWrite() rmw.Increment(familyName, u.Email, 1) row, err := tbl.ApplyReadModifyWrite(ctx, u.Email, rmw) if err != nil { return &appError{err, "Error applying ReadModifyWrite to row: " + u.Email, http.StatusInternalServerError} } data := struct { Username, Logout string Visits uint64 }{ Username: u.Email, // Retrieve the most recently edited column. Visits: binary.BigEndian.Uint64(row[familyName][0].Value), Logout: logoutURL, } var buf bytes.Buffer if err := tmpl.Execute(&buf, data); err != nil { return &appError{err, "Error writing template", http.StatusInternalServerError} } buf.WriteTo(w) return nil }
func handleMainPage(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, "GET requests only", http.StatusMethodNotAllowed) return } if r.URL.Path != "/" { http.NotFound(w, r) return } ctx := appengine.NewContext(r) tic := time.Now() q := datastore.NewQuery("Greeting").Ancestor(guestbookKey(ctx)).Order("-Date").Limit(10) var gg []*Greeting if _, err := q.GetAll(ctx, &gg); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Errorf(ctx, "GetAll: %v", err) return } log.Infof(ctx, "Datastore lookup took %s", time.Since(tic).String()) log.Infof(ctx, "Rendering %d greetings", len(gg)) var email, logout, login string if u := user.Current(ctx); u != nil { logout, _ = user.LogoutURL(ctx, "/") email = u.Email } else { login, _ = user.LoginURL(ctx, "/") } data := struct { Greetings []*Greeting Login, Logout, Email string }{ Greetings: gg, Login: login, Logout: logout, Email: email, } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := tpl.ExecuteTemplate(w, "guestbook.html", data); err != nil { log.Errorf(ctx, "%v", err) } }
func handleSign(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "POST requests only", http.StatusMethodNotAllowed) return } ctx := appengine.NewContext(r) g := &Greeting{ Content: r.FormValue("content"), Date: time.Now(), } if u := user.Current(ctx); u != nil { g.Author = u.String() } key := datastore.NewIncompleteKey(ctx, "Greeting", guestbookKey(ctx)) if _, err := datastore.Put(ctx, key, g); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Redirect with 303 which causes the subsequent request to use GET. http.Redirect(w, r, "/", http.StatusSeeOther) }
func handle(w http.ResponseWriter, req *http.Request) { c := appengine.NewContext(req) u := user.Current(c) if u == nil { u, _ = user.CurrentOAuth(c, "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/appengine.apis", ) } if u == nil || !u.Admin { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusUnauthorized) io.WriteString(w, "You must be logged in as an administrator to access this.\n") return } if req.Header.Get("X-Appcfg-Api-Version") == "" { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusForbidden) io.WriteString(w, "This request did not contain a necessary header.\n") return } if req.Method != "POST" { // Response must be YAML. rtok := req.FormValue("rtok") if rtok == "" { rtok = "0" } w.Header().Set("Content-Type", "text/yaml; charset=utf-8") fmt.Fprintf(w, `{app_id: %q, rtok: %q}`, internal.FullyQualifiedAppID(c), rtok) return } defer req.Body.Close() body, err := ioutil.ReadAll(req.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) log.Errorf(c, "Failed reading body: %v", err) return } remReq := &pb.Request{} if err := proto.Unmarshal(body, remReq); err != nil { w.WriteHeader(http.StatusBadRequest) log.Errorf(c, "Bad body: %v", err) return } service, method := *remReq.ServiceName, *remReq.Method if !requestSupported(service, method) { w.WriteHeader(http.StatusBadRequest) log.Errorf(c, "Unsupported RPC /%s.%s", service, method) return } rawReq := &rawMessage{remReq.Request} rawRes := &rawMessage{} err = internal.Call(c, service, method, rawReq, rawRes) remRes := &pb.Response{} if err == nil { remRes.Response = rawRes.buf } else if ae, ok := err.(*internal.APIError); ok { remRes.ApplicationError = &pb.ApplicationError{ Code: &ae.Code, Detail: &ae.Detail, } } else { // This shouldn't normally happen. log.Errorf(c, "appengine/remote_api: Unexpected error of type %T: %v", err, err) remRes.ApplicationError = &pb.ApplicationError{ Code: proto.Int32(0), Detail: proto.String(err.Error()), } } out, err := proto.Marshal(remRes) if err != nil { // This should not be possible. w.WriteHeader(500) log.Errorf(c, "proto.Marshal: %v", err) return } log.Infof(c, "Spooling %d bytes of response to /%s.%s", len(out), service, method) w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Length", strconv.Itoa(len(out))) w.Write(out) }