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

Side by Side Diff: tools/perf/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, 7 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Test server to facilitate the data reduction proxy Telemetry tests.
2 //
3 // The goal is to keep the test logic in client side (Telemetry)
4 // as much as possible. This server will only return a resource
5 // and/or override the response as specified by the data encoded
6 // in the request URL queries.
7 //
8 // For example, on receiving the query
bengr 2014/04/25 20:30:34 Please add a much more verbose comment that explai
bolian 2014/04/30 17:35:34 Added ref link for running it with GAE. We should
9 // /default?respBody=bmV3IGJvZHk=&respHeader=eyJWaWEiOlsiVmlhMSIsIlZpYTIiXX0%3D& respStatus=204
10 // the server sends back a response with
11 // status code: 204
12 // response headers: "Via: Via1" and "Via: Via2"
13 // response body: "new body"
14 // where the overriding headers and body are base64 encoded in the request query .
15
16 package server
17
18 import (
19 "bytes"
20 "encoding/base64"
21 "encoding/json"
22 "errors"
23 "fmt"
24 "io"
25 "net/http"
26 "os"
27 "strconv"
28 )
29
30 func init() {
31 http.HandleFunc("/requestHeader", requestHeader)
32 http.HandleFunc("/resource", resource)
33 http.HandleFunc("/default", defaultResponse)
34 }
35
36 // requestHander returns request headers in response body as text.
37 func requestHeader(w http.ResponseWriter, r *http.Request) {
38 r.Header.Write(w)
39 }
40
41 // resource returns the content of a data file specified by "r=" query as the re sponse body.
42 // The response could be overridden by request queries.
43 // See parseOverrideQuery.
44 func resource(w http.ResponseWriter, r *http.Request) {
45 wroteBody, err := applyOverride(w, r)
46 if err != nil || wroteBody {
47 return
48 }
49 path, ok := r.URL.Query()["r"]
50 if !ok || len(path) != 1 {
51 w.WriteHeader(http.StatusBadRequest)
52 w.Write([]byte("no resource in query"))
53 return
54 }
55 if _, err := writeFromFile(w, path[0]); err != nil {
56 w.WriteHeader(http.StatusBadRequest)
57 w.Write([]byte(fmt.Sprintf("Failed to get %s: %v", path[0], err) ))
58 return
59 }
60 }
61
62 // defaultResponse returns "ok" as response body, if the body is not overridden.
63 // The response could be overridden by request queries.
64 // See parseOverrideQuery.
65 func defaultResponse(w http.ResponseWriter, r *http.Request) {
66 wroteBody, err := applyOverride(w, r)
67 if err != nil {
68 return
69 }
70 if !wroteBody {
71 w.Write([]byte("ok"))
72 }
73 }
74
75 type override struct {
76 status int
77 header http.Header
78 body io.Reader
79 }
80
81 // parseOverrideQuery parses the queries in r and returns an override.
82 // It supports the following queries:
83 // "respStatus": an integer to override response status code;
84 // "respHeader": base64 encoded JSON data to override the response headers;
85 // "respBody": base64 encoded JSON data to override the response body.
86 func parseOverrideQuery(r *http.Request) (*override, error) {
87 q := r.URL.Query()
88 resp := &override{0, nil, nil}
89 if v, ok := q["respStatus"]; ok && len(v) == 1 && len(v[0]) > 0 {
90 status, err := strconv.ParseInt(v[0], 10, 0)
91 if err != nil {
92 return nil, errors.New(fmt.Sprintf("respStatus: %v", err ))
93 }
94 resp.status = int(status)
95 }
96 if v, ok := q["respHeader"]; ok && len(v) == 1 && len(v[0]) > 0 {
97 // Example header after base64 decoding:
98 // {"Via": ["Telemetry Test", "Test2"], "Name": ["XYZ"], "Cache -Control": ["public"]}
99 headerValue, err := base64.URLEncoding.DecodeString(v[0])
100 if err != nil {
101 return nil, errors.New(fmt.Sprintf("Decoding respHeader: %v", err))
102 }
103 var header http.Header
104 err = json.Unmarshal(headerValue, &header)
105 if err != nil {
106 return nil, errors.New(
107 fmt.Sprintf("Unmarlshal (%s) error: %v", string( headerValue), err))
108 }
109 resp.header = header
110 }
111 if v, ok := q["respBody"]; ok && len(v) == 1 && len(v[0]) > 0 {
112 body, err := base64.URLEncoding.DecodeString(v[0])
113 if err != nil {
114 return nil, errors.New(
115 fmt.Sprintf("Decoding respBody error: %v", err))
116 }
117 resp.body = bytes.NewBuffer(body)
118 }
119 return resp, nil
120 }
121
122 // applyOverride applies the override queries in r to w and returns whether the response
123 // body is overridden.
124 func applyOverride(w http.ResponseWriter, r *http.Request) (wroteBody bool, err error) {
125 resp, err := parseOverrideQuery(r)
126 if err != nil {
127 w.WriteHeader(http.StatusBadRequest)
128 w.Write([]byte(err.Error()))
129 return false, err
130 }
131 headers := w.Header()
132 if resp.header != nil {
133 for k, v := range resp.header {
134 headers[k] = v
135 }
136 }
137 if resp.status > 0 {
138 w.WriteHeader(resp.status)
139 }
140 if resp.body != nil {
141 _, err := io.Copy(w, resp.body)
142 return true, err
143 }
144 return false, nil
145 }
146
147 func writeFromFile(w io.Writer, filename string) (int64, error) {
148 f, err := os.Open(filename)
149 if err != nil {
150 return 0, err
151 }
152 return io.Copy(w, f)
153 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698