Beispiel #1
0
// This downgrades an http.Response object to HTTP 1.0, which is necessary in the case where the
// original client request was 1.0.
func DowngradeResponse(resp *http.Response, req *http.Request) {
	resp.Proto = "HTTP/1.0"
	resp.ProtoMajor = 1
	resp.ProtoMinor = 0

	if strings.Contains(strings.ToLower(req.Header.Get("Connection")), "keep-alive") {
		resp.Header.Set("Connection", "keep-alive")
		resp.Close = false
	} else {
		resp.Close = true
	}
}
Beispiel #2
0
func (res *HTTPResponseEvent) ToResponse() *http.Response {
	raw := new(http.Response)
	raw.Proto = "HTTP"
	raw.ProtoMajor = 1
	raw.ProtoMinor = 1
	//raw.Close = true
	raw.ContentLength = int64(res.Content.Len())
	raw.Header = make(http.Header)
	raw.StatusCode = int(res.Status)
	res.SetHeader("Content-Length", strconv.Itoa(res.Content.Len()))
	for i := 0; i < len(res.Headers); i++ {
		header := res.Headers[i]
		if strings.EqualFold(header.Name, "Set-Cookie") || strings.EqualFold(header.Name, "Set-Cookie2") {
			tmp := strings.Split(header.Value, ",")
			if len(tmp) > 1 {
				var vlist list.List
				for _, v := range tmp {
					if (!strings.Contains(v, "=") || strings.Index(v, "=") > strings.Index(v, ";")) && vlist.Len() > 0 {
						v = vlist.Back().Value.(string) + "," + v
						vlist.Remove(vlist.Back())
						vlist.PushBack(v)
						//headerValues.add(headerValues.removeLast() + "," + v);
					} else {
						vlist.PushBack(v)
					}
				}
				e := vlist.Front()
				for {
					if e == nil {
						break
					}
					raw.Header.Add(header.Name, e.Value.(string))
					e = e.Next()
				}
			} else {
				raw.Header.Add(header.Name, header.Value)
			}
		} else {
			raw.Header.Add(header.Name, header.Value)
		}
	}
	if raw.ContentLength > 0 {
		raw.Body = ioutil.NopCloser(&res.Content)
	}
	return raw
}
Beispiel #3
0
func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {

	body, err := ioutil.ReadAll(req.Body)

	var in pb.RunQueryRequest
	var resp http.Response
	if err = proto.Unmarshal(body, &in); err != nil {
		// Get back an error
		resp = http.Response{
			StatusCode: http.StatusBadRequest,
		}
	} else {
		// Run our fake query and serialize the response
		var out pb.RunQueryResponse
		err := t.Handler(&in, &out)
		if err != nil {

			resp = http.Response{
				StatusCode: http.StatusBadRequest,
			}
		} else {
			payload, err := proto.Marshal(&out)
			if err != nil {
				resp = http.Response{
					StatusCode: http.StatusBadRequest,
				}
			} else {
				resp = http.Response{
					StatusCode: http.StatusOK,
					Body:       ioutil.NopCloser(bytes.NewBuffer(payload)),
				}
			}

		}
	}

	// Set common response fields
	resp.Proto = "HTTP/1.0"
	resp.ProtoMajor = 1
	resp.ProtoMinor = 1
	if resp.Body == nil {
		resp.Body = ioutil.NopCloser(strings.NewReader(""))
	}

	return &resp, nil
}
Beispiel #4
0
// NewNotification returns a notification response with a specific body content.
func NewNotification(body *bytes.Buffer) *http.Response {
	resp := new(http.Response)
	resp.Status = "200 OK"
	resp.StatusCode = http.StatusOK
	resp.ProtoMajor = 1
	resp.ProtoMinor = 0
	resp.Body = ioutil.NopCloser(body)
	resp.ContentLength = int64(body.Len())
	resp.Header = map[string][]string{}
	resp.Header.Set("Content-Type", HTTPContentTypeHAPJson)

	// Will be ignored unfortunately and won't be fixed https://github.com/golang/go/issues/9304
	// Make sure to call FixProtocolSpecifier() instead
	resp.Proto = "EVENT/1.0"

	return resp
}
Beispiel #5
0
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
}
Beispiel #6
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)
}
Beispiel #7
0
func (p proxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.Body.Close()

	conn, _, err := w.(http.Hijacker).Hijack()
	if err != nil {
		log.Println("Failed to hijack connection in ProxyConnections.", err)
		return
	}

	defer conn.Close()

	if _, ok := conn.(*tls.Conn); !ok {
		log.Println("Recieved a non-TLS connection in ProxyConnections.")
		return
	}

	// Send the connection accepted response.
	res := new(http.Response)
	res.Status = "200 Connection Established"
	res.StatusCode = http.StatusOK
	res.Proto = "HTTP/1.1"
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	if err = res.Write(conn); err != nil {
		log.Println("Failed to send connection established message in ProxyConnections.", err)
		return
	}

	client, err := NewClientConn(conn, nil, 3, 1)
	if err != nil {
		log.Println("Error creating SPDY connection in ProxyConnections.", err)
		return
	}

	go client.Run()

	// Call user code.
	p.ProxyConnHandle(client)

	client.Close()
}
Beispiel #8
0
// New returns an event response for a characteristic from an accessory.
func New(a *accessory.Accessory, c *characteristic.Characteristic) (*http.Response, error) {
	body, err := Body(a, c)
	if err != nil {
		return nil, err
	}

	resp := new(http.Response)
	resp.Status = "200 OK"
	resp.StatusCode = http.StatusOK
	resp.ProtoMajor = 1
	resp.ProtoMinor = 0
	resp.Body = ioutil.NopCloser(body)
	resp.ContentLength = int64(body.Len())
	resp.Header = map[string][]string{}
	resp.Header.Set("Content-Type", netio.HTTPContentTypeHAPJson)
	// (brutella) Not sure if Date header must be set
	// resp.Header.Set("Date", netio.CurrentRFC1123Date())

	// Will be ignored unfortunately and won't be fixed https://github.com/golang/go/issues/9304
	// Make sure to call FixProtocolSpecifier() instead
	resp.Proto = "EVENT/1.0"

	return resp, nil
}
func (d *VirtualEndpoint) ServeHTTPForCache(w http.ResponseWriter, r *http.Request) *http.Response {

	// Check if we are even using this MW
	var stat RequestStatus
	var meta interface{}
	var found bool

	_, versionPaths, _, _ := d.TykMiddleware.Spec.GetVersionData(r)
	found, meta = d.TykMiddleware.Spec.CheckSpecMatchesStatus(r.URL.Path, r.Method, versionPaths, VirtualPath)

	if found {
		stat = StatusVirtualPath
	} else {
		return nil
	}

	if stat != StatusVirtualPath {
		return nil
	}

	t1 := time.Now().UnixNano()
	thisMeta := meta.(*tykcommon.VirtualMeta)

	// Create the proxy object
	defer r.Body.Close()
	originalBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error("Failed to read request body! ", err)
		return nil
	}

	thisRequestData := RequestObject{
		Headers: r.Header,
		Body:    string(originalBody),
		URL:     r.URL.Path,
	}

	// We need to copy the body _back_ for the decode
	r.Body = nopCloser{bytes.NewBuffer(originalBody)}
	r.ParseForm()
	thisRequestData.Params = r.Form

	asJsonRequestObj, encErr := json.Marshal(thisRequestData)
	if encErr != nil {
		log.Error("Failed to encode request object for virtual endpoint: ", encErr)
		return nil
	}

	// Encode the configuration data too
	configData, cErr := d.GetConfig()
	if cErr != nil {
		log.Error("Failed to parse configuration data: ", cErr)
		configData = make(map[string]string)
	}

	asJsonConfigData, encErr := json.Marshal(configData)
	if encErr != nil {
		log.Error("Failed to encode request object for virtual endpoint: ", encErr)
		return nil
	}

	var thisSessionState = SessionState{}
	var authHeaderValue = ""

	// Encode the session object (if not a pre-process)
	if thisMeta.UseSession {
		thisSessionState = context.Get(r, SessionData).(SessionState)
		authHeaderValue = context.Get(r, AuthHeaderValue).(string)
	}

	sessionAsJsonObj, sessEncErr := json.Marshal(thisSessionState)

	if sessEncErr != nil {
		log.Error("Failed to encode session for VM: ", sessEncErr)
		return nil
	}

	// Run the middleware
	returnRaw, _ := d.Spec.JSVM.VM.Run(thisMeta.ResponseFunctionName + `(` + string(asJsonRequestObj) + `, ` + string(sessionAsJsonObj) + `, ` + string(asJsonConfigData) + `);`)
	returnDataStr, _ := returnRaw.ToString()

	// Decode the return object
	newResponseData := VMResponseObject{}
	decErr := json.Unmarshal([]byte(returnDataStr), &newResponseData)

	if decErr != nil {
		log.Error("Failed to decode virtual endpoint response data on return from VM: ", decErr)
		log.Error("--> Returned: ", returnDataStr)
		return nil
	}

	// Save the sesison data (if modified)
	if thisMeta.UseSession {
		thisSessionState.MetaData = newResponseData.SessionMeta
		d.Spec.SessionManager.UpdateSession(authHeaderValue, thisSessionState, 0)
	}

	log.Debug("JSVM Virtual Endpoint execution took: (ns) ", time.Now().UnixNano()-t1)

	responseMessage := []byte(newResponseData.Response.Body)

	// Create an http.Response object so we can send it tot he cache middleware
	newResponse := new(http.Response)
	newResponse.Header = make(map[string][]string)

	requestTime := time.Now().UTC().Format(http.TimeFormat)

	for header, value := range newResponseData.Response.Headers {
		newResponse.Header.Add(header, value)
	}

	newResponse.ContentLength = int64(len(responseMessage))
	newResponse.Body = ioutil.NopCloser(bytes.NewReader(responseMessage))
	newResponse.StatusCode = newResponseData.Response.Code
	newResponse.Proto = "HTTP/1.0"
	newResponse.ProtoMajor = 1
	newResponse.ProtoMinor = 0
	newResponse.Header.Add("Server", "tyk")
	newResponse.Header.Add("Date", requestTime)

	// Handle response middleware
	ResponseHandler := ResponseChain{}

	chainErr := ResponseHandler.Go(d.TykMiddleware.Spec.ResponseChain, w, newResponse, r, &thisSessionState)
	if chainErr != nil {
		log.Error("Response chain failed! ", chainErr)
	}

	// Clone the response so we can save it
	copiedRes := new(http.Response)
	*copiedRes = *newResponse // includes shallow copies of maps, but okay

	defer newResponse.Body.Close()

	// Buffer body data
	var bodyBuffer bytes.Buffer
	bodyBuffer2 := new(bytes.Buffer)

	io.Copy(&bodyBuffer, newResponse.Body)
	*bodyBuffer2 = bodyBuffer

	// Create new ReadClosers so we can split output
	newResponse.Body = ioutil.NopCloser(&bodyBuffer)
	copiedRes.Body = ioutil.NopCloser(bodyBuffer2)

	d.HandleResponse(w, newResponse, &thisSessionState)

	// Record analytics
	go d.sh.RecordHit(w, r, 0)

	return copiedRes

}
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")
		}
	}
}
Beispiel #11
0
func (rt *RoundTripper) readResponse(c *e3x.Channel) (*http.Response, error) {
	var (
		r    = newClientPacketReadCloser(c)
		resp *http.Response
		err  error
	)

	{ // read the header
		var (
			headLenData [2]byte
			headLen     uint16
			headerData  []byte
			header      map[string]interface{}
		)

		_, err = io.ReadFull(r, headLenData[:])
		if err != nil {
			if err == io.EOF {
				return nil, io.ErrUnexpectedEOF
			}
			return nil, err
		}

		headLen = binary.BigEndian.Uint16(headLenData[:])
		headerData = make([]byte, headLen)
		_, err = io.ReadFull(r, headerData)
		if err != nil {
			if err == io.EOF {
				return nil, io.ErrUnexpectedEOF
			}
			return nil, err
		}

		err = json.Unmarshal(headerData, &header)
		if err != nil {
			return nil, err
		}

		resp = &http.Response{}

		if v, p := header[":status"]; p && v != nil {
			var i int

			switch w := v.(type) {
			case int:
				i = w
			case int64:
				i = int(w)
			case float32:
				i = int(w)
			case float64:
				i = int(w)
			}

			if i > 0 {
				resp.StatusCode = i
				resp.Status = http.StatusText(i)
			}

			delete(header, ":status")
		}
		if resp.StatusCode == 0 {
			return nil, &http.ProtocolError{"missing `status` header"}
		}

		resp.Header = make(http.Header, len(header))
		resp.Proto = "1.1"
		resp.ProtoMajor = 1
		resp.ProtoMinor = 1

		for k, v := range header {
			if s, ok := v.(string); !ok || s == "" {
				if k != "status" {
					resp.Header.Set(http.CanonicalHeaderKey(k), s)
				}
			}
		}
	}

	{ // set the body
		resp.Body = r
	}

	return resp, nil
}
Beispiel #12
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")
		}
	}
}
Beispiel #13
0
// 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
}
Beispiel #14
-1
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
}