Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Unified Diff: tools/chromeproxy_testserver/server.go

Issue 257663002: A Google AppEngine test server to facilitate chromeproxy Telemetry tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/chromeproxy_testserver/image/image1.png ('k') | tools/chromeproxy_testserver/server_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/chromeproxy_testserver/server.go
diff --git a/tools/chromeproxy_testserver/server.go b/tools/chromeproxy_testserver/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..c40bc5ee04fcfa75d784a137ff2f56ec614082d5
--- /dev/null
+++ b/tools/chromeproxy_testserver/server.go
@@ -0,0 +1,159 @@
+// Test server to facilitate the data reduction proxy Telemetry tests.
+//
+// The server runs at http://chromeproxy-test.appspot.com/. Please contact
+// people in OWNERS for server issues.
+//
+// For running an AppEngine Go server, see:
+// https://developers.google.com/appengine/docs/go/gettingstarted/introduction.
+//
+// The goal is to keep the test logic on the client side (Telemetry)
+// as much as possible. This server will only return a resource
+// and/or override the response as specified by the data encoded
+// in the request URL queries.
+//
+// For example, on receiving the query
+// /default?respBody=bmV3IGJvZHk=&respHeader=eyJWaWEiOlsiVmlhMSIsIlZpYTIiXX0%3D&respStatus=204
+// the server sends back a response with
+// Status code: 204
+// Additional response headers: "Via: Via1" and "Via: Via2"
+// Response body: "new body"
+// where the overriding headers and body are base64 encoded in the request query.
+
+package server
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "strconv"
+)
+
+func init() {
+ http.HandleFunc("/requestHeader", requestHeader)
+ http.HandleFunc("/resource", resource)
+ http.HandleFunc("/default", defaultResponse)
+}
+
+// requestHander returns request headers in response body as text.
+func requestHeader(w http.ResponseWriter, r *http.Request) {
+ r.Header.Write(w)
+}
+
+// resource returns the content of a data file specified by "r=" query as the response body.
+// The response could be overridden by request queries.
+// See parseOverrideQuery.
+func resource(w http.ResponseWriter, r *http.Request) {
+ wroteBody, err := applyOverride(w, r)
+ if err != nil || wroteBody {
+ return
+ }
+ path, ok := r.URL.Query()["r"]
+ if !ok || len(path) != 1 {
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte("no resource in query"))
+ return
+ }
+ if _, err := writeFromFile(w, path[0]); err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte(fmt.Sprintf("Failed to get %s: %v", path[0], err)))
+ return
+ }
+}
+
+// defaultResponse returns "ok" as response body, if the body is not overridden.
+// The response could be overridden by request queries.
+// See parseOverrideQuery.
+func defaultResponse(w http.ResponseWriter, r *http.Request) {
+ wroteBody, err := applyOverride(w, r)
+ if err != nil {
+ return
+ }
+ if !wroteBody {
+ w.Write([]byte("ok"))
+ }
+}
+
+type override struct {
+ status int
+ header http.Header
+ body io.Reader
+}
+
+// parseOverrideQuery parses the queries in r and returns an override.
+// It supports the following queries:
+// "respStatus": an integer to override response status code;
+// "respHeader": base64 encoded JSON data to override the response headers;
+// "respBody": base64 encoded JSON data to override the response body.
+func parseOverrideQuery(r *http.Request) (*override, error) {
+ q := r.URL.Query()
+ resp := &override{0, nil, nil}
+ if v, ok := q["respStatus"]; ok && len(v) == 1 && len(v[0]) > 0 {
+ status, err := strconv.ParseInt(v[0], 10, 0)
+ if err != nil {
+ return nil, errors.New(fmt.Sprintf("respStatus: %v", err))
+ }
+ resp.status = int(status)
+ }
+ if v, ok := q["respHeader"]; ok && len(v) == 1 && len(v[0]) > 0 {
+ // Example header after base64 decoding:
+ // {"Via": ["Telemetry Test", "Test2"], "Name": ["XYZ"], "Cache-Control": ["public"]}
+ headerValue, err := base64.URLEncoding.DecodeString(v[0])
+ if err != nil {
+ return nil, errors.New(fmt.Sprintf("Decoding respHeader: %v", err))
+ }
+ var header http.Header
+ err = json.Unmarshal(headerValue, &header)
+ if err != nil {
+ return nil, errors.New(
+ fmt.Sprintf("Unmarlshal (%s) error: %v", string(headerValue), err))
+ }
+ resp.header = header
+ }
+ if v, ok := q["respBody"]; ok && len(v) == 1 && len(v[0]) > 0 {
+ body, err := base64.URLEncoding.DecodeString(v[0])
+ if err != nil {
+ return nil, errors.New(
+ fmt.Sprintf("Decoding respBody error: %v", err))
+ }
+ resp.body = bytes.NewBuffer(body)
+ }
+ return resp, nil
+}
+
+// applyOverride applies the override queries in r to w and returns whether the response
+// body is overridden.
+func applyOverride(w http.ResponseWriter, r *http.Request) (wroteBody bool, err error) {
+ resp, err := parseOverrideQuery(r)
+ if err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte(err.Error()))
+ return false, err
+ }
+ headers := w.Header()
+ if resp.header != nil {
+ for k, v := range resp.header {
+ headers[k] = v
+ }
+ }
+ if resp.status > 0 {
+ w.WriteHeader(resp.status)
+ }
+ if resp.body != nil {
+ _, err := io.Copy(w, resp.body)
+ return true, err
+ }
+ return false, nil
+}
+
+func writeFromFile(w io.Writer, filename string) (int64, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return 0, err
+ }
+ return io.Copy(w, f)
+}
« no previous file with comments | « tools/chromeproxy_testserver/image/image1.png ('k') | tools/chromeproxy_testserver/server_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698