예제 #1
0
파일: param.go 프로젝트: huih/surfer
// 回写Request内容
func (self *Param) writeback(resp *http.Response) *http.Response {
	if resp == nil {
		resp = new(http.Response)
		resp.Request = new(http.Request)
	} else if resp.Request == nil {
		resp.Request = new(http.Request)
	}

	resp.Request.Method = self.method
	resp.Request.Header = self.header
	resp.Request.Host = self.url.Host

	return resp
}
예제 #2
0
// FileFetcher's Fetch() implementation
func (this *fileFetcherExtender) Fetch(u *url.URL, userAgent string, headRequest bool) (*http.Response, error) {
	var res *http.Response = new(http.Response)
	var req *http.Request
	var e error

	if req, e = http.NewRequest("GET", u.String(), nil); e != nil {
		panic(e)
	}

	// Prepare the pseudo-request
	req.Header.Add("User-Agent", userAgent)

	// Open the file specified as path in u, relative to testdata/[host]/
	f, e := os.Open(path.Join(FileFetcherBasePath, u.Host, u.Path))
	if e != nil {
		// Treat errors as 404s - file not found
		res.Status = "404 Not Found"
		res.StatusCode = 404
	} else {
		res.Status = "200 OK"
		res.StatusCode = 200
		res.Body = f
	}
	res.Request = req

	return res, e
}
예제 #3
0
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	var (
		hashname = hashname.H(req.URL.Host)
		c        *e3x.Channel
		resp     *http.Response
		err      error
	)

	x := rt.Endpoint.GetExchange(hashname)
	if x == nil {
		return nil, e3x.UnreachableEndpointError(hashname)
	}

	c, err = x.Open("thtp", true)
	if err != nil {
		c.Close()
		return nil, err
	}

	err = rt.writeRequest(req, c)
	if err != nil {
		c.Close()
		return nil, err
	}

	resp, err = rt.readResponse(c)
	if err != nil {
		c.Close()
		return nil, err
	}

	resp.Request = req
	return resp, nil
}
예제 #4
0
파일: response.go 프로젝트: pocke/httpmock
// ResponderFromResponse wraps an *http.Response in a Responder
func ResponderFromResponse(resp *http.Response) Responder {
	return func(req *http.Request) (*http.Response, error) {
		res := new(http.Response)
		*res = *resp
		res.Request = req
		return res, nil
	}
}
예제 #5
0
func RedirectResponse(req *http.Request, url string) *http.Response {
	res := new(http.Response)
	res.StatusCode = 302
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	res.ContentLength = 0
	res.Request = req
	res.Header = make(map[string][]string)
	res.Header.Set("Location", url)
	return res
}
예제 #6
0
파일: proxy.go 프로젝트: zalando/skipper
func (c *filterContext) Serve(res *http.Response) {
	res.Request = c.Request()

	if res.Header == nil {
		res.Header = make(http.Header)
	}

	if res.Body == nil {
		res.Body = &bodyBuffer{&bytes.Buffer{}}
	}

	c.servedWithResponse = true
	c.res = res
}
예제 #7
0
func SimpleResponse(req *http.Request, status int, headers http.Header, body string) *http.Response {
	res := new(http.Response)
	body_rdr := (*fixedResBody)(strings.NewReader(body))
	res.StatusCode = status
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	res.ContentLength = int64((*strings.Reader)(body_rdr).Len())
	res.Request = req
	res.Header = make(map[string][]string)
	res.Body = body_rdr
	if headers != nil {
		res.Header = headers
	}
	return res
}
예제 #8
0
// Generate an http.Response using the basic fields
func SimpleResponse(req *http.Request, status int, headers http.Header, contentLength int64, body io.Reader) *http.Response {
	res := new(http.Response)
	res.StatusCode = status
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	res.ContentLength = contentLength
	res.Request = req
	res.Header = make(map[string][]string)
	if body_rdr, ok := body.(io.ReadCloser); ok {
		res.Body = body_rdr
	} else if body != nil {
		res.Body = ioutil.NopCloser(body)
	}
	if headers != nil {
		res.Header = headers
	}
	return res
}
예제 #9
0
파일: transport.go 프로젝트: keichan34/spdy
func (r *response) Response() *http.Response {
	if r.Data == nil {
		r.Data = new(bytes.Buffer)
	}
	out := new(http.Response)
	out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode))
	out.StatusCode = r.StatusCode
	out.Proto = "HTTP/1.1"
	out.ProtoMajor = 1
	out.ProtoMinor = 1
	out.Header = r.Header
	out.Body = &readCloser{r.Data}
	out.ContentLength = int64(r.Data.Len())
	out.TransferEncoding = nil
	out.Close = true
	out.Trailer = make(http.Header)
	out.Request = r.Request
	return out
}
예제 #10
0
func (p *MockResponseWriter) String() string {
	resp := new(http.Response)
	resp.StatusCode = p.StatusCode
	resp.Proto = "HTTP/1.1"
	resp.ProtoMajor = 1
	resp.ProtoMinor = 1
	resp.Header = p.Headers
	resp.Body = ioutil.NopCloser(bytes.NewBuffer(p.Buffer.Bytes()))
	resp.ContentLength = int64(p.Buffer.Len())
	if p.Headers.Get("Transfer-Encoding") != "" {
		resp.TransferEncoding = []string{p.Headers.Get("Transfer-Encoding")}
	} else {
		resp.TransferEncoding = nil
	}
	resp.Close = p.Headers.Get("Connection") == "close"
	resp.Trailer = make(http.Header)
	resp.Request = p.Request
	b, _ := httputil.DumpResponse(resp, true)
	return string(b)
}
예제 #11
0
파일: handler.go 프로젝트: johnsonz/goproxy
func (h Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var err error

	remoteAddr := req.RemoteAddr

	// Prepare filter.Context
	ctx := filters.NewContext(req.Context(), h, h.Listener, rw, h.Branding)
	req = req.WithContext(ctx)

	// Enable transport http proxy
	if req.Method != "CONNECT" && !req.URL.IsAbs() {
		if req.URL.Scheme == "" {
			if req.TLS != nil && req.ProtoMajor == 1 {
				req.URL.Scheme = "https"
			} else {
				req.URL.Scheme = "http"
			}
		}

		if req.TLS != nil {
			if req.Host == "" {
				if req.URL.Host != "" {
					req.Host = req.URL.Host
				} else {
					req.Host = req.TLS.ServerName
				}
			}
			if req.URL.Host == "" {
				if req.Host != "" {
					req.URL.Host = req.Host
				} else {
					req.URL.Host = req.TLS.ServerName
				}
			}
		}
	}

	// Filter Request
	for _, f := range h.RequestFilters {
		ctx, req, err = f.Request(ctx, req)
		if req == filters.DummyRequest {
			return
		}
		if err != nil {
			if err != io.EOF {
				glog.Errorf("%s Filter Request %T error: %+v", remoteAddr, f, err)
			}
			return
		}
		// Update context for request
		req = req.WithContext(ctx)
	}

	if req.Body != nil {
		defer req.Body.Close()
	}

	// Filter Request -> Response
	var resp *http.Response
	for _, f := range h.RoundTripFilters {
		ctx, resp, err = f.RoundTrip(ctx, req)
		if resp == filters.DummyResponse {
			return
		}
		// Unexcepted errors
		if err != nil {
			filters.SetRoundTripFilter(ctx, f)
			glog.Errorf("%s Filter RoundTrip %T error: %+v", remoteAddr, f, err)
			http.Error(rw, h.FormatError(ctx, err), http.StatusBadGateway)
			return
		}
		// Update context for request
		req = req.WithContext(ctx)
		// A roundtrip filter give a response
		if resp != nil {
			resp.Request = req
			filters.SetRoundTripFilter(ctx, f)
			break
		}
	}

	// Filter Response
	for _, f := range h.ResponseFilters {
		if resp == nil || resp == filters.DummyResponse {
			return
		}
		ctx, resp, err = f.Response(ctx, resp)
		if err != nil {
			glog.Errorln("%s Filter %T Response error: %+v", remoteAddr, f, err)
			http.Error(rw, h.FormatError(ctx, err), http.StatusBadGateway)
			return
		}
		// Update context for request
		req = req.WithContext(ctx)
	}

	if resp == nil {
		glog.Errorln("%s Handler %#v Response empty response", remoteAddr, h)
		http.Error(rw, h.FormatError(ctx, fmt.Errorf("empty response")), http.StatusBadGateway)
		return
	}

	if resp.Header.Get("Content-Length") == "" && resp.ContentLength >= 0 {
		resp.Header.Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10))
	}
	for key, values := range resp.Header {
		for _, value := range values {
			rw.Header().Add(key, value)
		}
	}
	rw.WriteHeader(resp.StatusCode)
	if resp.Body != nil {
		defer resp.Body.Close()
		n, err := helpers.IOCopy(rw, resp.Body)
		if err != nil {
			if isClosedConnError(err) {
				glog.Infof("IOCopy %#v return %#v %T(%v)", resp.Body, n, err, err)
			} else {
				glog.Warningf("IOCopy %#v return %#v %T(%v)", resp.Body, n, err, err)
			}
		}
	}
}
예제 #12
0
파일: response.go 프로젝트: kr/spdy
// ReadResponse reads an HTTP response. The header is taken from h,
// which must include the SPDY-specific fields starting with ':'.
// If r is not nil, the body will be read from r. If t is not nil,
// the trailer will be taken from t after the body is finished.
func ReadResponse(h, t http.Header, r io.Reader, req *http.Request) (*http.Response, error) {
	for _, s := range badRespHeaderFields {
		if _, ok := h[s]; ok {
			return nil, &badStringError{"invalid header field", s}
		}
	}

	var err error
	resp := new(http.Response)
	resp.Request = req
	resp.Close = true
	resp.Header = make(http.Header)
	copyHeader(resp.Header, h)
	f := strings.SplitN(h.Get(":status"), " ", 2)
	var s string
	if len(f) > 1 {
		s = f[1]
	}
	resp.Status = f[0] + " " + s
	resp.StatusCode, err = strconv.Atoi(f[0])
	if err != nil {
		return nil, &badStringError{"malformed HTTP status code", f[0]}
	}
	resp.Proto = h.Get(":version")
	var ok bool
	resp.ProtoMajor, resp.ProtoMinor, ok = http.ParseHTTPVersion(resp.Proto)
	if !ok {
		return nil, &badStringError{"malformed HTTP version", resp.Proto}
	}

	realLength, err := fixLength(true, resp.StatusCode, req.Method, resp.Header)
	if err != nil {
		return nil, err
	}
	if req.Method == "HEAD" {
		if n, err := parseContentLength(h.Get("Content-Length")); err != nil {
			return nil, err
		} else {
			resp.ContentLength = n
		}
	} else {
		resp.ContentLength = realLength
	}

	switch {
	case realLength == 0:
		r = eofReader
	case realLength > 0:
		if r == nil {
			// TODO(kr): return error
		}
		r = io.LimitReader(r, realLength)
	}
	if r == nil {
		r = eofReader
	}
	body := &body{r: r}
	resp.Body = body
	if t != nil {
		body.hdr = resp
		body.trailer = t
	}
	return resp, nil
}
예제 #13
0
func filterByUrl(w icap.ResponseWriter, req *icap.Request) {
	h := w.Header()
	h.Set("ISTag", ISTag)
	h.Set("Service", "SquidBlocker filter ICAP service")

	if *debug {
		fmt.Fprintln(os.Stderr, "Printing the full ICAP request")
		fmt.Fprintln(os.Stderr, req)
		fmt.Fprintln(os.Stderr, req.Request)
	}
	switch req.Method {
	case "OPTIONS":
		h.Set("Methods", "REQMOD, RESPMOD")
		h.Set("Options-TTL", "1800")
		h.Set("Allow", "204")
		h.Set("Preview", "0")
		h.Set("Transfer-Preview", "*")
		h.Set("Max-Connections", "4000")
		h.Set("X-Include", "X-Client-IP, X-Authenticated-Groups, X-Authenticated-User, X-Subscriber-Id")
		w.WriteHeader(200, nil, false)
	case "REQMOD":

		// Check if the method is either OPTIONS\GET\POST\PUT etc
		// Also to analyse the request stucutre to verify what is the current one used
		// based on the RFC section at: http://tools.ietf.org/html/rfc7230#section-5.3
		// Treat the CONNECT method in a special way due to the fact that it cannot actually be modified.
		checkhost := ""
		port := "0"
		answer := *defaultAnswer
		var err error
		if *debug {
			fmt.Fprintln(os.Stderr, "Default CASE. Request to host: "+req.Request.URL.Host+", Request Method: "+req.Request.Method)
			fmt.Fprintln(os.Stderr, "The full url from the ICAP client request: "+req.Request.URL.String())
		}

		checkhost, port, err = net.SplitHostPort(req.Request.URL.Host)
		if err != nil {
			_ = err
			checkhost = req.Request.URL.Host
		}

		if port != "0" {
			if *debug {
				fmt.Fprintln(os.Stderr, "Rquest with port: "+port)
			}
		}

		if req.Request.Method == "CONNECT" && len(checkhost) > 0 && port != "0" {
			answer = check_tcp(checkhost, port)
		} else {
			answer = check(req.Request.URL.String())
		}

		if *debug {
			fmt.Fprintln(os.Stderr, "ERRlog: reporting answer size => "+strconv.Itoa(len(answer)))
			fmt.Fprintln(os.Stderr, "ERRlog: reporitng answer => "+answer+", for =>"+req.Request.URL.String())
		}

		// The next part comes to make sure that a DUNO respnse will be handled as the default answer/action
		if strings.HasPrefix(answer, "DUNO") {
			answer = *defaultAnswer + " rate=100 default_answer=yes"
			if *debug {
				fmt.Fprintln(os.Stderr, "ERRlog: reporting answer startsWith => \"DUNO\", taking default action")
				if len(*defaultAnswer) > 0 {
					fmt.Fprintln(os.Stderr, req.Request.URL.String()+" "+*defaultAnswer+" rate=40 default_answer=yes")
				} else {
					fmt.Fprintln(os.Stderr, req.Request.URL.String()+" OK state=DUNO")
				}
			}
		}

		if strings.HasPrefix(answer, "OK") {
			if *debug {
				fmt.Fprintln(os.Stderr, "OK response and sending 204 back")
			}
			w.WriteHeader(204, nil, false)
			return
		}
		if strings.HasPrefix(answer, "ERR") {
			if *debug {
				fmt.Fprintln(os.Stderr, "ERR response and sending 307 redirection back")
			}
			resp := new(http.Response)
			resp.Status = "307 SquidBlocker this url has been filtered!"
			resp.StatusCode = 307
			resp.Proto = "HTTP/1.1"
			resp.ProtoMajor = 1
			resp.ProtoMinor = 1
			myMap := make(map[string][]string)
			//What if it is a connect request
			myMap["Location"] = append(myMap["Location"], *block_page+"?url="+url.QueryEscape(req.Request.URL.String()))
			resp.Header = myMap
			//resp.Body = ioutil.NopCloser(bytes.NewBufferString(body))
			//resp.ContentLength = int64(len(body))
			resp.Request = req.Request
			w.WriteHeader(200, resp, true)
			return
		}
		if *debug {
			fmt.Fprintln(os.Stderr, "Unknown asnwer and scenario, not adapting the request")
		}
		w.WriteHeader(204, nil, false)
		return
	case "RESPMOD":
		w.WriteHeader(204, nil, false)
	default:
		w.WriteHeader(405, nil, false)
		if *debug {
			fmt.Fprintln(os.Stderr, "Invalid request method")
		}
	}
}
예제 #14
0
파일: replay.go 프로젝트: nathanjordan/dvr
// This is the RoundTrip() call when we are in replay mode.
func (r *roundTripper) replay(req *http.Request) (*http.Response, error) {
	// Ensure that the replay system is setup.
	isSetup.Do(r.replaySetup)

	// Read the body into a buffer.
	buffer := &bytes.Buffer{}
	var reqErr error
	if req.Body != nil {
		_, reqErr = io.Copy(buffer, req.Body)
	}

	// Since this function deals with the requestList we need to lock.
	requestLock.Lock()
	defer requestLock.Unlock()

	// Figure out which match function to use.
	f := Matcher
	if f == nil {
		f = matcher
	}

	// Walk through the objects in our archive list and see if any of them
	// match the incoming request.
	rrSource := &RequestResponse{
		Request:          req,
		RequestBody:      buffer.Bytes(),
		RequestBodyError: reqErr,
	}

	var rrMatch *RequestResponse
	for _, rr := range requestList {
		if f(rrSource, rr) {
			rrMatch = rr
			break
		}
	}
	if rrMatch == nil {
		messageLines := []string{
			"Matcher didn't match any execeted queries.\n",
			"Details of the failed request:",
			"",
			fmt.Sprintf("URL: %s", req.URL.String()),
			fmt.Sprintf("Method: %s", req.Method),
		}
		if len(req.Header) > 0 {
			messageLines = append(messageLines, "\nHeaders:")
			for key, value := range req.Header {
				messageLines = append(messageLines,
					fmt.Sprintf("    %s: %s", key, strings.Join(value, ", ")))
			}
		}
		if len(req.Trailer) > 0 {
			messageLines = append(messageLines, "\nTrailers:")
			for key, value := range req.Trailer {
				messageLines = append(messageLines,
					fmt.Sprintf("    %s: %s", key, strings.Join(value, ", ")))
			}
		}
		if len(buffer.Bytes()) > 0 {
			// This block is written a little funky in order to make testing
			// easier since it doesn't if/else as much.
			messageLines = append(messageLines, "Body:")
			length := len(buffer.Bytes())
			warning := ""
			if length > 512 {
				length = 512
				warning = "... (content truncated by dvr)"
			}
			messageLines = append(messageLines,
				string(buffer.Bytes()[:length])+warning)
		}
		panicIfError(fmt.Errorf(strings.Join(messageLines, "\n")))
	}

	// Check to see if the response was an error when recorded.
	if rrMatch.Response == nil {
		return nil, rrMatch.Error
	}

	// Setup our response object.
	resp := new(http.Response)
	*resp = *rrMatch.Response
	resp.Request = req

	// Lastly we need to setup a bodyWriter for the Body. This will allow the
	// client to read the body we captured and it will return the error we
	// captured (if any) rather than EOF.
	resp.Body = &bodyWriter{
		data: rrMatch.ResponseBody,
		err:  rrMatch.ResponseBodyError,
	}

	// And lastly we return the response.
	return resp, rrMatch.Error
}
예제 #15
0
func toShadowD(w icap.ResponseWriter, req *icap.Request) {
	local_debug := false
	if strings.Contains(req.URL.RawQuery, "debug=1") {
		local_debug = true
	}

	h := w.Header()
	h.Set("ISTag", ISTag)
	h.Set("Service", "Shadower ICAP to WAF Connector")

	if *debug {
		fmt.Fprintln(os.Stderr, "Printing the full ICAP request")
		fmt.Fprintln(os.Stderr, req)
		fmt.Fprintln(os.Stderr, req.Request)
		fmt.Fprintln(os.Stderr, req.Response)
	}
	switch req.Method {
	case "OPTIONS":
		h.Set("Methods", "REQMOD")
		h.Set("Options-TTL", "1800")
		h.Set("Allow", "204, 206")
		h.Set("Preview", "0")
		h.Set("Transfer-Preview", "*")
		h.Set("Max-Connections", *maxConnections)
		h.Set("X-Include", "X-Client-Ip, X-Authenticated-Groups, X-Authenticated-User, X-Subscriber-Id")
		w.WriteHeader(200, nil, false)
	case "REQMOD":
		modified := false
		nullBody := false
		allow206 := false
		allow204 := false
		xclientip := false

		if _, allow204Exists := req.Header["Allow"]; allow204Exists {
			if strings.Contains(req.Header["Allow"][0], "204") {
				allow204 = true
			}
		}

		if _, allow206Exists := req.Header["Allow"]; allow206Exists {
			if strings.Contains(req.Header["Allow"][0], "206") {
				allow206 = true
			}
		}

		if _, xclientipExists := req.Header["X-Client-Ip"]; xclientipExists {
			if len(req.Header["X-Client-Ip"][0]) > 1 {
				xclientip = true
			}
		}

		if _, encapsulationExists := req.Header["Encapsulated"]; encapsulationExists {
			if strings.Contains(req.Header["Encapsulated"][0], "null-body=") {
				nullBody = true
			}
		}

		if *debug || local_debug {
			for k, v := range req.Header {
				fmt.Fprintln(os.Stderr, "The ICAP headers:")
				fmt.Fprintln(os.Stderr, "key size:", len(req.Header[k]))
				fmt.Fprintln(os.Stderr, "key:", k, "value:", v)
			}
		}

		_, _, _, _ = nullBody, allow206, modified, allow204
		if xclientip {
			req.Request.RemoteAddr = req.Header["X-Client-Ip"][0]
		}

		if wrongMethod(req) {
			if *debug {
				fmt.Println("This request has a", req.Request.Method, "method which is not being analyzed")
			}
			w.WriteHeader(204, nil, false)
			return
		}

		if *debug || local_debug {
			for k, v := range req.Request.Header {
				fmt.Fprintln(os.Stderr, "key:", k, "value:", v)
			}
		}

		// Send the request to ShadowD
		// If an attack(5,6) was declared then send a custom 500 page
		// If OK then send a 204 back
		var resStatus = 1
		shodowdres, err := shadowServer.SendToShadowd(req.Request)
		newmap := make(map[string]interface{})
		err = json.Unmarshal([]byte(shodowdres), &newmap)
		if err != nil {
			panic(err)
		}

		switch int(newmap["status"].(float64)) {
		case shadowd.STATUS_OK:
			if *debug || local_debug {
				fmt.Println("Request reported, OK")
			}
			w.WriteHeader(204, nil, false)
			return
		case shadowd.STATUS_BAD_REQUEST:
			resStatus = 400
		case shadowd.STATUS_BAD_SIGNATURE:
			resStatus = 503
		case shadowd.STATUS_BAD_JSON:
			resStatus = 504
		case shadowd.STATUS_ATTACK:
			resStatus = 505
		case shadowd.STATUS_CRITICAL_ATTACK:
			resStatus = 506
		default:
			resStatus = 500
		}

		resp := new(http.Response)
		resp.Status = "Internal Server Error"
		resp.StatusCode = resStatus
		resp.Proto = req.Request.Proto
		resp.ProtoMajor = req.Request.ProtoMajor
		resp.ProtoMinor = req.Request.ProtoMinor
		resp.Request = req.Request
		myHeaderMap := make(map[string][]string)
		resp.Header = myHeaderMap
		resp.Header.Set("X-Ngtech-Proxy", "Shadower")
		resp.Header.Set("X-Shadower", strconv.Itoa(resStatus))
		resp.Header.Set("Content-Type", "text/html")
		resp.Header.Set("Content-Length", strconv.Itoa(len(internalerrorpage)))
		w.WriteHeader(200, resp, true)
		io.WriteString(w, internalerrorpage)
		return

		if *debug {
			fmt.Println("end of the line 204 response!.. Shouldn't happen.")
		}
		w.WriteHeader(204, nil, false)
		return
	case "RESPMOD":
		w.WriteHeader(204, nil, false)
		return
	default:
		w.WriteHeader(405, nil, false)
		if *debug || local_debug {
			fmt.Fprintln(os.Stderr, "Invalid request method")
		}
	}
}
예제 #16
0
func (h Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var err error

	remoteAddr := req.RemoteAddr

	// Prepare filter.Context
	ctx := filters.NewContext(h.Listener, rw, req)

	// Enable transport http proxy
	if req.Method != "CONNECT" && !req.URL.IsAbs() {
		if req.URL.Scheme == "" {
			if req.TLS != nil && req.ProtoMajor == 1 {
				req.URL.Scheme = "https"
			} else {
				req.URL.Scheme = "http"
			}
		}
		if req.URL.Host == "" {
			if req.Host != "" {
				req.URL.Host = req.Host
			} else {
				if req.TLS != nil {
					req.URL.Host = req.TLS.ServerName
				}
			}
		}
	}

	// Filter Request
	for _, f := range h.RequestFilters {
		ctx, req, err = f.Request(ctx, req)
		// A roundtrip filter hijacked
		if ctx.Hijacked() {
			return
		}
		if err != nil {
			if err != io.EOF {
				glog.Errorf("%s Filter Request %T(%v) error: %v", remoteAddr, f, f, err)
			}
			return
		}
	}

	// Filter Request -> Response
	var resp *http.Response
	for _, f := range h.RoundTripFilters {
		ctx, resp, err = f.RoundTrip(ctx, req)
		// A roundtrip filter hijacked
		if ctx.Hijacked() {
			return
		}
		// Unexcepted errors
		if err != nil {
			glog.Errorf("%s Filter RoundTrip %T(%v) error: %v", remoteAddr, f, f, err)
			return
		}
		// A roundtrip filter give a response
		if resp != nil {
			resp.Request = req
			break
		}
	}

	// Filter Response
	for _, f := range h.ResponseFilters {
		if resp == nil {
			return
		}
		ctx, resp, err = f.Response(ctx, resp)
		if err != nil {
			glog.Errorf("%s Filter Response %T(%v) error: %v", remoteAddr, f, f, err)
			return
		}
	}

	if resp == nil {
		return
	}

	for key, values := range resp.Header {
		for _, value := range values {
			rw.Header().Add(key, value)
		}
	}
	rw.WriteHeader(resp.StatusCode)
	if resp.Body != nil {
		defer resp.Body.Close()
		n, err := IoCopy(rw, resp.Body)
		if err != nil {
			glog.Errorf("IoCopy %#v return %#v %s", resp.Body, n, err)
		}
	}
}
예제 #17
-1
파일: response.go 프로젝트: vonwenm/spdy
func (r *Response) Response() *http.Response {
	out := new(http.Response)

	r.headerM.Lock()
	out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode))
	out.StatusCode = r.StatusCode
	out.Header = r.Header
	r.headerM.Unlock()

	out.Proto = "HTTP/1.1"
	out.ProtoMajor = 1
	out.ProtoMinor = 1

	r.dataM.Lock()
	if r.data == nil {
		out.Body = &ReadCloser{new(bytes.Buffer)}
	} else if unrequestedGzip(r) {
		// User-agents MUST support gzip compression.
		// Regardless of the Accept-Encoding sent by the user-agent, the server may
		// always send content encoded with gzip or deflate encoding.
		r.data.Prep()
		out.Header.Del("Content-Encoding")
		out.Header.Del("Content-Length")
		out.ContentLength = -1
		out.Body = &gzipReader{body: r.data}
	} else {
		r.data.Prep()
		out.Body = r.data
		out.ContentLength = r.data.written
	}
	r.dataM.Unlock()

	out.TransferEncoding = nil
	out.Close = true
	out.Trailer = make(http.Header)
	out.Request = r.Request
	return out
}