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