1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package messageview
16
17import (
18	"bufio"
19	"bytes"
20	"compress/flate"
21	"compress/gzip"
22	"io"
23	"io/ioutil"
24	"net/http"
25	"strings"
26	"testing"
27
28	"github.com/google/martian/v3/proxyutil"
29)
30
31func TestRequestViewHeadersOnly(t *testing.T) {
32	body := strings.NewReader("body content")
33	req, err := http.NewRequest("GET", "http://example.com/path?k=v", body)
34	if err != nil {
35		t.Fatalf("http.NewRequest(): got %v, want no error", err)
36	}
37	req.ContentLength = int64(body.Len())
38	req.Header.Set("Request-Header", "true")
39
40	mv := New()
41	mv.SkipBody(true)
42	if err := mv.SnapshotRequest(req); err != nil {
43		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
44	}
45
46	got, err := ioutil.ReadAll(mv.HeaderReader())
47	if err != nil {
48		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
49	}
50
51	hdrwant := "GET http://example.com/path?k=v HTTP/1.1\r\n" +
52		"Host: example.com\r\n" +
53		"Content-Length: 12\r\n" +
54		"Request-Header: true\r\n\r\n"
55
56	if !bytes.Equal(got, []byte(hdrwant)) {
57		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
58	}
59
60	br, err := mv.BodyReader()
61	if err != nil {
62		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
63	}
64
65	if _, err := br.Read(nil); err != io.EOF {
66		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want io.EOF", err)
67	}
68
69	r, err := mv.Reader()
70	if err != nil {
71		t.Fatalf("mv.Reader(): got %v, want no error", err)
72	}
73	got, err = ioutil.ReadAll(r)
74	if err != nil {
75		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
76	}
77
78	if want := []byte(hdrwant); !bytes.Equal(got, want) {
79		t.Fatalf("mv.Read(): got %q, want %q", got, want)
80	}
81}
82
83func TestRequestView(t *testing.T) {
84	body := strings.NewReader("body content")
85	req, err := http.NewRequest("GET", "http://example.com/path?k=v", body)
86	if err != nil {
87		t.Fatalf("http.NewRequest(): got %v, want no error", err)
88	}
89	req.Header.Set("Request-Header", "true")
90
91	// Force Content Length to be unset to simulate lack of Content-Length and
92	// Transfer-Encoding which is valid.
93	req.ContentLength = -1
94
95	mv := New()
96	if err := mv.SnapshotRequest(req); err != nil {
97		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
98	}
99
100	got, err := ioutil.ReadAll(mv.HeaderReader())
101	if err != nil {
102		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
103	}
104
105	hdrwant := "GET http://example.com/path?k=v HTTP/1.1\r\n" +
106		"Host: example.com\r\n" +
107		"Request-Header: true\r\n\r\n"
108
109	if !bytes.Equal(got, []byte(hdrwant)) {
110		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
111	}
112
113	br, err := mv.BodyReader()
114	if err != nil {
115		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
116	}
117
118	got, err = ioutil.ReadAll(br)
119	if err != nil {
120		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
121	}
122
123	bodywant := "body content"
124	if !bytes.Equal(got, []byte(bodywant)) {
125		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
126	}
127
128	r, err := mv.Reader()
129	if err != nil {
130		t.Fatalf("mv.Reader(): got %v, want no error", err)
131	}
132	got, err = ioutil.ReadAll(r)
133	if err != nil {
134		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
135	}
136
137	if want := []byte(hdrwant + bodywant); !bytes.Equal(got, want) {
138		t.Fatalf("mv.Read(): got %q, want %q", got, want)
139	}
140
141	// Sanity check to ensure it still parses.
142	if _, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(got))); err != nil {
143		t.Fatalf("http.ReadRequest(): got %v, want no error", err)
144	}
145}
146
147func TestRequestViewSkipBodyUnlessContentType(t *testing.T) {
148	req, err := http.NewRequest("GET", "http://example.com", strings.NewReader("body content"))
149	if err != nil {
150		t.Fatalf("http.NewRequest(): got %v, want no error", err)
151	}
152	req.ContentLength = 12
153	req.Header.Set("Content-Type", "text/plain; charset=utf-8")
154
155	mv := New()
156	mv.SkipBodyUnlessContentType("text/plain")
157	if err := mv.SnapshotRequest(req); err != nil {
158		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
159	}
160
161	br, err := mv.BodyReader()
162	if err != nil {
163		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
164	}
165
166	got, err := ioutil.ReadAll(br)
167	if err != nil {
168		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
169	}
170
171	bodywant := "body content"
172	if !bytes.Equal(got, []byte(bodywant)) {
173		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
174	}
175
176	req.Header.Set("Content-Type", "image/png")
177	mv = New()
178	mv.SkipBodyUnlessContentType("text/plain")
179	if err := mv.SnapshotRequest(req); err != nil {
180		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
181	}
182
183	br, err = mv.BodyReader()
184	if err != nil {
185		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
186	}
187
188	if _, err := br.Read(nil); err != io.EOF {
189		t.Fatalf("br.Read(): got %v, want io.EOF", err)
190	}
191}
192
193func TestRequestViewChunkedTransferEncoding(t *testing.T) {
194	req, err := http.NewRequest("GET", "http://example.com/path?k=v", strings.NewReader("body content"))
195	if err != nil {
196		t.Fatalf("http.NewRequest(): got %v, want no error", err)
197	}
198	req.TransferEncoding = []string{"chunked"}
199	req.Header.Set("Trailer", "Trailer-Header")
200	req.Trailer = http.Header{
201		"Trailer-Header": []string{"true"},
202	}
203
204	mv := New()
205	if err := mv.SnapshotRequest(req); err != nil {
206		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
207	}
208
209	got, err := ioutil.ReadAll(mv.HeaderReader())
210	if err != nil {
211		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
212	}
213
214	hdrwant := "GET http://example.com/path?k=v HTTP/1.1\r\n" +
215		"Host: example.com\r\n" +
216		"Transfer-Encoding: chunked\r\n" +
217		"Trailer: Trailer-Header\r\n\r\n"
218
219	if !bytes.Equal(got, []byte(hdrwant)) {
220		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
221	}
222
223	br, err := mv.BodyReader()
224	if err != nil {
225		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
226	}
227
228	got, err = ioutil.ReadAll(br)
229	if err != nil {
230		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
231	}
232
233	bodywant := "c\r\nbody content\r\n0\r\n"
234	if !bytes.Equal(got, []byte(bodywant)) {
235		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
236	}
237
238	got, err = ioutil.ReadAll(mv.TrailerReader())
239	if err != nil {
240		t.Fatalf("ioutil.ReadAll(mv.TrailerReader()): got %v, want no error", err)
241	}
242
243	trailerwant := "Trailer-Header: true\r\n"
244	if !bytes.Equal(got, []byte(trailerwant)) {
245		t.Fatalf("mv.TrailerReader(): got %q, want %q", got, trailerwant)
246	}
247
248	r, err := mv.Reader()
249	if err != nil {
250		t.Fatalf("mv.Reader(): got %v, want no error", err)
251	}
252	got, err = ioutil.ReadAll(r)
253	if err != nil {
254		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
255	}
256
257	if want := []byte(hdrwant + bodywant + trailerwant); !bytes.Equal(got, want) {
258		t.Fatalf("mv.Read(): got %q, want %q", got, want)
259	}
260
261	// Sanity check to ensure it still parses.
262	if _, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(got))); err != nil {
263		t.Fatalf("http.ReadRequest(): got %v, want no error", err)
264	}
265}
266
267func TestRequestViewDecodeGzipContentEncoding(t *testing.T) {
268	body := new(bytes.Buffer)
269	gw := gzip.NewWriter(body)
270	gw.Write([]byte("body content"))
271	gw.Flush()
272	gw.Close()
273
274	req, err := http.NewRequest("GET", "http://example.com/path?k=v", body)
275	if err != nil {
276		t.Fatalf("http.NewRequest(): got %v, want no error", err)
277	}
278	req.TransferEncoding = []string{"chunked"}
279	req.Header.Set("Content-Encoding", "gzip")
280
281	mv := New()
282	if err := mv.SnapshotRequest(req); err != nil {
283		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
284	}
285
286	got, err := ioutil.ReadAll(mv.HeaderReader())
287	if err != nil {
288		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
289	}
290
291	hdrwant := "GET http://example.com/path?k=v HTTP/1.1\r\n" +
292		"Host: example.com\r\n" +
293		"Transfer-Encoding: chunked\r\n" +
294		"Content-Encoding: gzip\r\n\r\n"
295
296	if !bytes.Equal(got, []byte(hdrwant)) {
297		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
298	}
299
300	br, err := mv.BodyReader(Decode())
301	if err != nil {
302		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
303	}
304
305	got, err = ioutil.ReadAll(br)
306	if err != nil {
307		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, wt o error", err)
308	}
309
310	bodywant := "body content"
311
312	if !bytes.Equal(got, []byte(bodywant)) {
313		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
314	}
315
316	r, err := mv.Reader(Decode())
317	if err != nil {
318		t.Fatalf("mv.Reader(): got %v, want no error", err)
319	}
320	got, err = ioutil.ReadAll(r)
321	if err != nil {
322		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
323	}
324
325	if want := []byte(hdrwant + bodywant + "\r\n"); !bytes.Equal(got, want) {
326		t.Fatalf("mv.Read(): got %q, want %q", got, want)
327	}
328}
329
330func TestRequestViewDecodeDeflateContentEncoding(t *testing.T) {
331	body := new(bytes.Buffer)
332	dw, err := flate.NewWriter(body, -1)
333	if err != nil {
334		t.Fatalf("flate.NewWriter(): got %v, want no error", err)
335	}
336	dw.Write([]byte("body content"))
337	dw.Flush()
338	dw.Close()
339
340	req, err := http.NewRequest("GET", "http://example.com/path?k=v", body)
341	if err != nil {
342		t.Fatalf("http.NewRequest(): got %v, want no error", err)
343	}
344	req.TransferEncoding = []string{"chunked"}
345	req.Header.Set("Content-Encoding", "deflate")
346
347	mv := New()
348	if err := mv.SnapshotRequest(req); err != nil {
349		t.Fatalf("SnapshotRequest(): got %v, want no error", err)
350	}
351
352	got, err := ioutil.ReadAll(mv.HeaderReader())
353	if err != nil {
354		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
355	}
356
357	hdrwant := "GET http://example.com/path?k=v HTTP/1.1\r\n" +
358		"Host: example.com\r\n" +
359		"Transfer-Encoding: chunked\r\n" +
360		"Content-Encoding: deflate\r\n\r\n"
361
362	if !bytes.Equal(got, []byte(hdrwant)) {
363		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
364	}
365
366	br, err := mv.BodyReader(Decode())
367	if err != nil {
368		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
369	}
370
371	got, err = ioutil.ReadAll(br)
372	if err != nil {
373		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
374	}
375
376	bodywant := "body content"
377
378	if !bytes.Equal(got, []byte(bodywant)) {
379		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
380	}
381
382	r, err := mv.Reader(Decode())
383	if err != nil {
384		t.Fatalf("mv.Reader(): got %v, want no error", err)
385	}
386	got, err = ioutil.ReadAll(r)
387	if err != nil {
388		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
389	}
390
391	if want := []byte(hdrwant + bodywant + "\r\n"); !bytes.Equal(got, want) {
392		t.Fatalf("mv.Read(): got %q, want %q", got, want)
393	}
394}
395
396func TestResponseViewHeadersOnly(t *testing.T) {
397	body := strings.NewReader("body content")
398	res := proxyutil.NewResponse(200, body, nil)
399	res.ContentLength = 12
400	res.Header.Set("Response-Header", "true")
401
402	mv := New()
403	mv.SkipBody(true)
404	if err := mv.SnapshotResponse(res); err != nil {
405		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
406	}
407
408	got, err := ioutil.ReadAll(mv.HeaderReader())
409	if err != nil {
410		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
411	}
412
413	hdrwant := "HTTP/1.1 200 OK\r\n" +
414		"Content-Length: 12\r\n" +
415		"Response-Header: true\r\n\r\n"
416
417	if !bytes.Equal(got, []byte(hdrwant)) {
418		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
419	}
420
421	br, err := mv.BodyReader()
422	if err != nil {
423		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
424	}
425
426	if _, err := br.Read(nil); err != io.EOF {
427		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want io.EOF", err)
428	}
429
430	r, err := mv.Reader()
431	if err != nil {
432		t.Fatalf("mv.Reader(): got %v, want no error", err)
433	}
434	got, err = ioutil.ReadAll(r)
435	if err != nil {
436		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
437	}
438
439	if want := []byte(hdrwant); !bytes.Equal(got, want) {
440		t.Fatalf("mv.Read(): got %q, want %q", got, want)
441	}
442}
443
444func TestResponseView(t *testing.T) {
445	body := strings.NewReader("body content")
446	res := proxyutil.NewResponse(200, body, nil)
447	res.ContentLength = 12
448	res.Header.Set("Response-Header", "true")
449
450	mv := New()
451	if err := mv.SnapshotResponse(res); err != nil {
452		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
453	}
454
455	got, err := ioutil.ReadAll(mv.HeaderReader())
456	if err != nil {
457		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
458	}
459
460	hdrwant := "HTTP/1.1 200 OK\r\n" +
461		"Content-Length: 12\r\n" +
462		"Response-Header: true\r\n\r\n"
463
464	if !bytes.Equal(got, []byte(hdrwant)) {
465		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
466	}
467
468	br, err := mv.BodyReader()
469	if err != nil {
470		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
471	}
472
473	got, err = ioutil.ReadAll(br)
474	if err != nil {
475		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
476	}
477
478	bodywant := "body content"
479	if !bytes.Equal(got, []byte(bodywant)) {
480		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
481	}
482
483	r, err := mv.Reader()
484	if err != nil {
485		t.Fatalf("mv.Reader(): got %v, want no error", err)
486	}
487	got, err = ioutil.ReadAll(r)
488	if err != nil {
489		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
490	}
491
492	if want := []byte(hdrwant + bodywant); !bytes.Equal(got, want) {
493		t.Fatalf("mv.Read(): got %q, want %q", got, want)
494	}
495
496	// Sanity check to ensure it still parses.
497	if _, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(got)), nil); err != nil {
498		t.Fatalf("http.ReadResponse(): got %v, want no error", err)
499	}
500}
501
502func TestResponseViewSkipBodyUnlessContentType(t *testing.T) {
503	res := proxyutil.NewResponse(200, strings.NewReader("body content"), nil)
504	res.ContentLength = 12
505	res.Header.Set("Content-Type", "text/plain; charset=utf-8")
506
507	mv := New()
508	mv.SkipBodyUnlessContentType("text/plain")
509	if err := mv.SnapshotResponse(res); err != nil {
510		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
511	}
512
513	br, err := mv.BodyReader()
514	if err != nil {
515		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
516	}
517
518	got, err := ioutil.ReadAll(br)
519	if err != nil {
520		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
521	}
522
523	bodywant := "body content"
524	if !bytes.Equal(got, []byte(bodywant)) {
525		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
526	}
527
528	res.Header.Set("Content-Type", "image/png")
529	mv = New()
530	mv.SkipBodyUnlessContentType("text/plain")
531	if err := mv.SnapshotResponse(res); err != nil {
532		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
533	}
534
535	br, err = mv.BodyReader()
536	if err != nil {
537		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
538	}
539
540	if _, err := br.Read(nil); err != io.EOF {
541		t.Fatalf("br.Read(): got %v, want io.EOF", err)
542	}
543}
544
545func TestResponseViewChunkedTransferEncoding(t *testing.T) {
546	body := strings.NewReader("body content")
547	res := proxyutil.NewResponse(200, body, nil)
548	res.TransferEncoding = []string{"chunked"}
549	res.Header.Set("Trailer", "Trailer-Header")
550	res.Trailer = http.Header{
551		"Trailer-Header": []string{"true"},
552	}
553
554	mv := New()
555	if err := mv.SnapshotResponse(res); err != nil {
556		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
557	}
558
559	got, err := ioutil.ReadAll(mv.HeaderReader())
560	if err != nil {
561		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
562	}
563
564	hdrwant := "HTTP/1.1 200 OK\r\n" +
565		"Transfer-Encoding: chunked\r\n" +
566		"Trailer: Trailer-Header\r\n\r\n"
567
568	if !bytes.Equal(got, []byte(hdrwant)) {
569		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
570	}
571
572	br, err := mv.BodyReader()
573	if err != nil {
574		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
575	}
576
577	got, err = ioutil.ReadAll(br)
578	if err != nil {
579		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, want no error", err)
580	}
581
582	bodywant := "c\r\nbody content\r\n0\r\n"
583	if !bytes.Equal(got, []byte(bodywant)) {
584		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
585	}
586
587	got, err = ioutil.ReadAll(mv.TrailerReader())
588	if err != nil {
589		t.Fatalf("ioutil.ReadAll(mv.TrailerReader()): got %v, want no error", err)
590	}
591
592	trailerwant := "Trailer-Header: true\r\n"
593	if !bytes.Equal(got, []byte(trailerwant)) {
594		t.Fatalf("mv.TrailerReader(): got %q, want %q", got, trailerwant)
595	}
596
597	r, err := mv.Reader()
598	if err != nil {
599		t.Fatalf("mv.Reader(): got %v, want no error", err)
600	}
601	got, err = ioutil.ReadAll(r)
602	if err != nil {
603		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
604	}
605
606	if want := []byte(hdrwant + bodywant + trailerwant); !bytes.Equal(got, want) {
607		t.Fatalf("mv.Read(): got %q, want %q", got, want)
608	}
609
610	// Sanity check to ensure it still parses.
611	if _, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(got)), nil); err != nil {
612		t.Fatalf("http.ReadResponse(): got %v, want no error", err)
613	}
614}
615
616func TestResponseViewDecodeGzipContentEncoding(t *testing.T) {
617	body := new(bytes.Buffer)
618	gw := gzip.NewWriter(body)
619	gw.Write([]byte("body content"))
620	gw.Flush()
621	gw.Close()
622
623	res := proxyutil.NewResponse(200, body, nil)
624	res.TransferEncoding = []string{"chunked"}
625	res.Header.Set("Content-Encoding", "gzip")
626
627	mv := New()
628	if err := mv.SnapshotResponse(res); err != nil {
629		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
630	}
631
632	got, err := ioutil.ReadAll(mv.HeaderReader())
633	if err != nil {
634		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
635	}
636
637	hdrwant := "HTTP/1.1 200 OK\r\n" +
638		"Transfer-Encoding: chunked\r\n" +
639		"Content-Encoding: gzip\r\n\r\n"
640
641	if !bytes.Equal(got, []byte(hdrwant)) {
642		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
643	}
644
645	br, err := mv.BodyReader(Decode())
646	if err != nil {
647		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
648	}
649
650	got, err = ioutil.ReadAll(br)
651	if err != nil {
652		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, wt o error", err)
653	}
654
655	bodywant := "body content"
656
657	if !bytes.Equal(got, []byte(bodywant)) {
658		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
659	}
660
661	r, err := mv.Reader(Decode())
662	if err != nil {
663		t.Fatalf("mv.Reader(): got %v, want no error", err)
664	}
665	got, err = ioutil.ReadAll(r)
666	if err != nil {
667		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
668	}
669
670	if want := []byte(hdrwant + bodywant + "\r\n"); !bytes.Equal(got, want) {
671		t.Fatalf("mv.Read(): got %q, want %q", got, want)
672	}
673}
674
675func TestResponseViewDecodeGzipContentEncodingPartial(t *testing.T) {
676	bodywant := "partial content"
677	res := proxyutil.NewResponse(206, strings.NewReader(bodywant), nil)
678	res.TransferEncoding = []string{"chunked"}
679	res.Header.Set("Content-Encoding", "gzip")
680
681	mv := New()
682	if err := mv.SnapshotResponse(res); err != nil {
683		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
684	}
685	br, err := mv.BodyReader(Decode())
686	if err != nil {
687		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
688	}
689
690	got, err := ioutil.ReadAll(br)
691	if err != nil {
692		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, wt o error", err)
693	}
694	if !bytes.Equal(got, []byte(bodywant)) {
695		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
696	}
697}
698
699func TestResponseViewDecodeDeflateContentEncoding(t *testing.T) {
700	body := new(bytes.Buffer)
701	dw, err := flate.NewWriter(body, -1)
702	if err != nil {
703		t.Fatalf("flate.NewWriter(): got %v, want no error", err)
704	}
705	dw.Write([]byte("body content"))
706	dw.Flush()
707	dw.Close()
708
709	res := proxyutil.NewResponse(200, body, nil)
710	res.TransferEncoding = []string{"chunked"}
711	res.Header.Set("Content-Encoding", "deflate")
712
713	mv := New()
714	if err := mv.SnapshotResponse(res); err != nil {
715		t.Fatalf("SnapshotResponse(): got %v, want no error", err)
716	}
717
718	got, err := ioutil.ReadAll(mv.HeaderReader())
719	if err != nil {
720		t.Fatalf("ioutil.ReadAll(mv.HeaderReader()): got %v, want no error", err)
721	}
722
723	hdrwant := "HTTP/1.1 200 OK\r\n" +
724		"Transfer-Encoding: chunked\r\n" +
725		"Content-Encoding: deflate\r\n\r\n"
726
727	if !bytes.Equal(got, []byte(hdrwant)) {
728		t.Fatalf("mv.HeaderReader(): got %q, want %q", got, hdrwant)
729	}
730
731	br, err := mv.BodyReader(Decode())
732	if err != nil {
733		t.Fatalf("mv.BodyReader(): got %v, want no error", err)
734	}
735
736	got, err = ioutil.ReadAll(br)
737	if err != nil {
738		t.Fatalf("ioutil.ReadAll(mv.BodyReader()): got %v, wt o error", err)
739	}
740
741	bodywant := "body content"
742
743	if !bytes.Equal(got, []byte(bodywant)) {
744		t.Fatalf("mv.BodyReader(): got %q, want %q", got, bodywant)
745	}
746
747	r, err := mv.Reader(Decode())
748	if err != nil {
749		t.Fatalf("mv.Reader(): got %v, want no error", err)
750	}
751	got, err = ioutil.ReadAll(r)
752	if err != nil {
753		t.Fatalf("ioutil.ReadAll(mv.Reader()): got %v, want no error", err)
754	}
755
756	if want := []byte(hdrwant + bodywant + "\r\n"); !bytes.Equal(got, want) {
757		t.Fatalf("mv.Read(): got %q, want %q", got, want)
758	}
759}
760