Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 } | |
| OLD | NEW |