Beispiel #1
2
func send(req *http.Request) (resp *http.Response, err os.Error) {
	addr := req.URL.Host
	if !hasPort(addr) {
		addr += ":http"
	}
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}

	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req.Method)
	if err != nil {
		conn.Close()
		return nil, err
	}

	r := io.Reader(reader)
	if n := resp.ContentLength; n != -1 {
		r = io.LimitReader(r, n)
	}
	resp.Body = readClose{r, conn}

	return
}
func (t *logTransport) RoundTrip(req *http.Request) (*http.Response, os.Error) {
	var buf bytes.Buffer

	os.Stdout.Write([]byte("\n[request]\n"))
	if req.Body != nil {
		req.Body = ioutil.NopCloser(&readButCopy{req.Body, &buf})
	}
	req.Write(os.Stdout)
	if req.Body != nil {
		req.Body = ioutil.NopCloser(&buf)
	}
	os.Stdout.Write([]byte("\n[/request]\n"))

	res, err := t.rt.RoundTrip(req)

	fmt.Printf("[response]\n")
	if err != nil {
		fmt.Printf("ERROR: %v", err)
	} else {
		body := res.Body
		res.Body = nil
		res.Write(os.Stdout)
		if body != nil {
			res.Body = ioutil.NopCloser(&echoAsRead{body})
		}
	}

	return res, err
}
Beispiel #3
0
func send(req *http.Request) (resp *http.Response, err os.Error) {
	addr := req.URL.Host
	if !hasPort(addr) {
		addr += ":http"
	}
	conn, err := net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}

	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, "GET")
	if err != nil {
		conn.Close()
		return nil, err
	}

	r := io.Reader(reader)
	if v := resp.GetHeader("Content-Length"); v != "" {
		n, err := strconv.Atoi64(v)
		if err != nil {
			//			return nil, &badStringError{"invalid Content-Length", v}
		}
		r = io.LimitReader(r, n)
	}
	resp.Body = readClose{r, conn}

	return
}
Beispiel #4
0
// execute a request; date it, sign it, send it
func (bucket *Bucket) Execute(req *http.Request) (resp *http.Response, err os.Error) {
	// time stamp it
	date := time.LocalTime().Format(time.RFC1123)
	req.Header["Date"] = date

	// sign the request
	bucket.Sign(req)

	// open a connection
	conn, err := net.Dial("tcp", "", req.URL.Host+":"+req.URL.Scheme)
	if err != nil {
		return nil, err
	}

	// send the request
	req.Write(conn)

	// now read the response
	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req.Method)
	if err != nil {
		return nil, err
	}

	return
}
Beispiel #5
0
func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.Write(os.Stdout)
	for _, route := range routes {
		if route.pattern.MatchString(r.RawURL) {
			route.handler(h.Repo, w, r)
			break
		}
	}
}
Beispiel #6
0
func SendTo(req *http.Request, conn net.Conn) (e os.Error) {
	// Write our request struct to the connection in http wire format.
	e = req.Write(conn)
	if e != nil {
		fmt.Println("Error writing request:", e)
	}
	fmt.Printf("Wrote request\n")
	return
}
Beispiel #7
0
func (proxy *Proxy) ServeHTTP(conn *http.Conn, req *http.Request) {

	// Open a connection to the Hub.
	hubconn, err := net.Dial("tcp", "", remoteAddr)
	if err != nil {
		if debugMode {
			fmt.Printf("Couldn't connect to remote %s: %v\n", remoteHost, err)
		}
		return
	}

	hub := tls.Client(hubconn, tlsconf.Config)
	defer hub.Close()

	// Modify the request Host: header.
	req.Host = remoteHost

	// Send the request to the Hub.
	err = req.Write(hub)
	if err != nil {
		if debugMode {
			fmt.Printf("Error writing to the hub: %v\n", err)
		}
		return
	}

	// Parse the response from the Hub.
	resp, err := http.ReadResponse(bufio.NewReader(hub), req.Method)
	if err != nil {
		if debugMode {
			fmt.Printf("Error parsing response from the hub: %v\n", err)
		}
		return
	}

	// Set the received headers back to the initial connection.
	for k, v := range resp.Header {
		conn.SetHeader(k, v)
	}

	// Read the full response body.
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		if debugMode {
			fmt.Printf("Error reading response from the hub: %v\n", err)
		}
		resp.Body.Close()
		return
	}

	// Write the response body back to the initial connection.
	resp.Body.Close()
	conn.WriteHeader(resp.StatusCode)
	conn.Write(body)

}
Beispiel #8
0
func send(req *http.Request) (resp *http.Response, err os.Error) {
	if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
		return nil, nil
	}

	addr := req.URL.Host
	if !hasPort(addr) {
		addr += ":" + req.URL.Scheme
	}
	/*info := req.URL.Userinfo
	  if len(info) > 0 {
	      enc := base64.URLEncoding
	      encoded := make([]byte, enc.EncodedLen(len(info)))
	      enc.Encode(encoded, []byte(info))
	      if req.Header == nil {
	          req.Header = make(map[string]string)
	      }
	      req.Header["Authorization"] = "Basic " + string(encoded)
	  }
	*/
	var conn io.ReadWriteCloser
	if req.URL.Scheme == "http" {
		conn, err = net.Dial("tcp", addr)
	} else { // https
		conn, err = tls.Dial("tcp", addr, nil)
	}
	if err != nil {
		return nil, err
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}

	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req)
	if err != nil {
		conn.Close()
		return nil, err
	}

	resp.Body = readClose{resp.Body, conn}

	return
}
Beispiel #9
0
func send(req *http.Request) (resp *http.Response, err os.Error) {
	//dump, _ := http.DumpRequest(req, true)
	//fmt.Fprintf(os.Stderr, "%s", dump)
	//fmt.Fprintf(os.Stderr, "\n--- body:\n%s\n---", bodyString(req.Body))
	if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
		return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
	}

	addr := req.URL.Host
	var conn net.Conn
	switch req.URL.Scheme {
	case "http":
		if !hasPort(addr) {
			addr += ":http"
		}

		conn, err = net.Dial("tcp", addr)
	case "https":
		if !hasPort(addr) {
			addr += ":https"
		}

		conn, err = tls.Dial("tcp", addr, nil)
	}
	if err != nil {
		return nil, err
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}

	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req)
	if err != nil {
		conn.Close()
		return nil, err
	}

	resp.Body = readClose{resp.Body, conn}

	return
}
Beispiel #10
0
func sendPost(postRequest *http.Request) (body string, err os.Error) {
	// Create and use TCP connection (lifted mostly wholesale from http.send)
	conn, err := net.Dial("tcp", "api.flickr.com:80")
	defer conn.Close()

	if err != nil {
		return "", err
	}
	postRequest.Write(conn)

	reader := bufio.NewReader(conn)
	resp, err := http.ReadResponse(reader, postRequest.Method)
	if err != nil {
		return "", err
	}
	rawBody, _ := ioutil.ReadAll(resp.Body)

	return string(rawBody), nil
}
Beispiel #11
0
func main() {
	url := "http://twitter.com/statuses/public_timeline.json"
	var req http.Request
	req.URL, _ = http.ParseURL(url)
	addr := req.URL.Host
	addr += ":http"
	conn, _ := net.Dial("tcp", "", addr)
	_ = req.Write(conn)
	reader := bufio.NewReader(conn)
	resp, _ := http.ReadResponse(reader)
	r := io.Reader(reader)
	if v := resp.GetHeader("Content-Length"); v != "" {
		n, _ := strconv.Atoi64(v)
		r = io.LimitReader(r, n)
	}
	resp.Body = readClose{r, conn}
	b, _ := io.ReadAll(resp.Body)
	resp.Body.Close()
	fmt.Println(string(b))
}
Beispiel #12
0
func send(req *http.Request) (resp *http.Response, err os.Error) {
	if req.URL.Scheme != "http" {
		return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
	}

	addr := req.URL.Host
	if !hasPort(addr) {
		addr += ":http"
	}
	info := req.URL.Userinfo
	if len(info) > 0 {
		enc := base64.URLEncoding
		encoded := make([]byte, enc.EncodedLen(len(info)))
		enc.Encode(encoded, strings.Bytes(info))
		if req.Header == nil {
			req.Header = make(map[string]string)
		}
		req.Header["Authorization"] = "Basic " + string(encoded)
	}
	conn, err := net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}

	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req.Method)
	if err != nil {
		conn.Close()
		return nil, err
	}

	resp.Body = readClose{resp.Body, conn}

	return
}
Beispiel #13
0
// execute a request; date it, sign it, send it
// note: specialcase is temporary hack to set Content-Length: 0 when needed
func (p *Propolis) SignAndExecute(req *http.Request, specialcase bool) (resp *http.Response, err os.Error) {
	// time stamp it
	date := time.LocalTime().Format(time.RFC1123)
	req.Header.Set("Date", date)

	// sign the request
	p.SignRequest(req)

	// open a connection
	conn, err := net.Dial("tcp", req.URL.Host+":"+req.URL.Scheme)
	if err != nil {
		return nil, err
	}

	// send the request
	if specialcase {
		var buf bytes.Buffer
		req.Write(&buf)
		fixed := bytes.Replace(buf.Bytes(),
			[]byte("User-Agent: Go http package\r\n"),
			[]byte("User-Agent: Go http package\r\nContent-Length: 0\r\n"), 1)
		_, err = conn.Write(fixed)
	} else {
		err = req.Write(conn)
	}
	if err != nil {
		return
	}

	// now read the response
	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req)
	if err != nil {
		return nil, err
	}

	return
}
Beispiel #14
0
func (frontend *Frontend) ServeHTTP(conn *http.Conn, req *http.Request) {

	if frontend.enforceHost && req.Host != frontend.officialHost {
		conn.SetHeader("Location", frontend.officialRedirectURL)
		conn.WriteHeader(http.StatusMovedPermanently)
		conn.Write(frontend.officialRedirectHTML)
		logRequest(http.StatusMovedPermanently, req.Host, conn)
		return
	}

	originalHost := req.Host

	// Open a connection to the App Engine server.
	gaeConn, err := net.Dial("tcp", "", frontend.gaeAddr)
	if err != nil {
		if debugMode {
			fmt.Printf("Couldn't connect to remote %s: %v\n", frontend.gaeHost, err)
		}
		serveError502(conn, originalHost)
		return
	}

	var gae net.Conn

	if frontend.gaeTLS {
		gae = tls.Client(gaeConn, tlsconf.Config)
		defer gae.Close()
	} else {
		gae = gaeConn
	}

	// Modify the request Host: header.
	req.Host = frontend.gaeHost

	// Send the request to the App Engine server.
	err = req.Write(gae)
	if err != nil {
		if debugMode {
			fmt.Printf("Error writing to App Engine: %v\n", err)
		}
		serveError502(conn, originalHost)
		return
	}

	// Parse the response from App Engine.
	resp, err := http.ReadResponse(bufio.NewReader(gae), req.Method)
	if err != nil {
		if debugMode {
			fmt.Printf("Error parsing response from App Engine: %v\n", err)
		}
		serveError502(conn, originalHost)
		return
	}

	// Read the full response body.
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		if debugMode {
			fmt.Printf("Error reading response from App Engine: %v\n", err)
		}
		serveError502(conn, originalHost)
		resp.Body.Close()
		return
	}

	// Set the received headers back to the initial connection.
	for k, v := range resp.Header {
		conn.SetHeader(k, v)
	}

	// Write the response body back to the initial connection.
	resp.Body.Close()
	conn.WriteHeader(resp.StatusCode)
	conn.Write(body)

	logRequest(resp.StatusCode, originalHost, conn)

}
Beispiel #15
0
func (frontend *Frontend) ServeHTTP(conn http.ResponseWriter, req *http.Request) {

	originalHost := req.Host

	// Redirect all requests to the "official" public host if the Host header
	// doesn't match.
	if !frontend.isValidHost(originalHost) {
		conn.Header().Set("Location", frontend.RedirectURL)
		conn.WriteHeader(http.StatusMovedPermanently)
		conn.Write(frontend.RedirectHTML)
		frontend.Log(HTTPS_REDIRECT, http.StatusMovedPermanently, originalHost, req)
		return
	}

	// Return the HTTP 503 error page if we're in maintenance mode.
	if frontend.MaintenanceMode {
		headers := conn.Header()
		headers.Set("Content-Type", "text/html; charset=utf-8")
		headers.Set("Content-Length", frontend.Error503Length)
		conn.WriteHeader(http.StatusServiceUnavailable)
		conn.Write(frontend.Error503)
		frontend.Log(HTTPS_MAINTENANCE, http.StatusServiceUnavailable, originalHost, req)
		return
	}

	reqPath := req.URL.Path

	// Handle requests for any files exposed within the static directory.
	if staticFile, ok := frontend.StaticFiles[reqPath]; ok {
		expires := time.SecondsToUTC(time.Seconds() + frontend.StaticMaxAge)
		headers := conn.Header()
		headers.Set("Expires", expires.Format(http.TimeFormat))
		headers.Set("Cache-Control", frontend.StaticCache)
		headers.Set("Etag", staticFile.ETag)
		if req.Header.Get("If-None-Match") == staticFile.ETag {
			conn.WriteHeader(http.StatusNotModified)
			frontend.Log(HTTPS_STATIC, http.StatusNotModified, originalHost, req)
			return
		}
		// Special case /.well-known/oauth.json?callback= requests.
		if reqPath == "/.well-known/oauth.json" && req.URL.RawQuery != "" {
			query, err := http.ParseQuery(req.URL.RawQuery)
			if err != nil {
				logging.Error("Error parsing oauth.json query string %q: %s",
					req.URL.RawQuery, err)
				frontend.ServeError400(conn, originalHost, req)
				return
			}
			if callbackList, found := query["callback"]; found {
				callback := callbackList[0]
				if callback != "" {
					respLen := len(callback) + len(staticFile.Content) + 2
					headers.Set("Content-Type", "text/javascript")
					headers.Set("Content-Length", fmt.Sprintf("%d", respLen))
					conn.WriteHeader(http.StatusOK)
					conn.Write([]byte(callback))
					conn.Write([]byte{'('})
					conn.Write(staticFile.Content)
					conn.Write([]byte{')'})
					frontend.Log(HTTPS_STATIC, http.StatusOK, originalHost, req)
					return
				}
			}
		}
		headers.Set("Content-Type", staticFile.Mimetype)
		headers.Set("Content-Length", staticFile.Size)
		conn.WriteHeader(http.StatusOK)
		conn.Write(staticFile.Content)
		frontend.Log(HTTPS_STATIC, http.StatusOK, originalHost, req)
		return
	}

	if frontend.LiveMode {

		// Handle WebSocket requests.
		if strings.HasPrefix(reqPath, frontend.WebsocketPrefix) {
			websocket.Handler(frontend.getWebSocketHandler()).ServeHTTP(conn, req)
			return
		}

		// Handle long-polling Comet requests.
		if strings.HasPrefix(reqPath, frontend.CometPrefix) {
			query, err := http.ParseQuery(req.URL.RawQuery)
			if err != nil {
				logging.Error("Error parsing Comet query string %q: %s",
					req.URL.RawQuery, err)
				frontend.ServeError400(conn, originalHost, req)
				return
			}
			queryReq, found := query["q"]
			if !found {
				frontend.ServeError400(conn, originalHost, req)
				return
			}
			response, status := getLiveItems(queryReq[0])
			headers := conn.Header()
			headers.Set("Content-Type", "application/json")
			headers.Set("Content-Length", fmt.Sprintf("%d", len(response)))
			conn.WriteHeader(status)
			conn.Write(response)
			frontend.Log(HTTPS_COMET, status, originalHost, req)
			return
		}

	}

	// Open a connection to the upstream server.
	upstreamConn, err := net.Dial("tcp", frontend.upstreamAddr)
	if err != nil {
		logging.Error("Couldn't connect to upstream: %s", err)
		frontend.ServeError502(conn, originalHost, req)
		return
	}

	var clientIP string
	var upstream net.Conn

	splitPoint := strings.LastIndex(req.RemoteAddr, ":")
	if splitPoint == -1 {
		clientIP = req.RemoteAddr
	} else {
		clientIP = req.RemoteAddr[0:splitPoint]
	}

	if frontend.upstreamTLS {
		upstream = tls.Client(upstreamConn, tlsconf.Config)
		defer upstream.Close()
	} else {
		upstream = upstreamConn
	}

	// Modify the request Host: and User-Agent: headers.
	req.Host = frontend.upstreamHost
	req.Header.Set(
		"User-Agent",
		fmt.Sprintf("%s, %s, %s", req.UserAgent(), clientIP, originalHost))

	// Send the request to the upstream server.
	err = req.Write(upstream)
	if err != nil {
		logging.Error("Error writing to the upstream server: %s", err)
		frontend.ServeError502(conn, originalHost, req)
		return
	}

	// Parse the response from upstream.
	resp, err := http.ReadResponse(bufio.NewReader(upstream), req)
	if err != nil {
		logging.Error("Error parsing response from upstream: %s", err)
		frontend.ServeError502(conn, originalHost, req)
		return
	}

	defer resp.Body.Close()

	// Get the original request header.
	headers := conn.Header()

	// Set a variable to hold the X-Live header value if present.
	var liveLength int

	if frontend.LiveMode {
		xLive := resp.Header.Get("X-Live")
		if xLive != "" {
			// If the X-Live header was set, parse it into an int.
			liveLength, err = strconv.Atoi(xLive)
			if err != nil {
				logging.Error("Error converting X-Live header value %q: %s", xLive, err)
				frontend.ServeError500(conn, originalHost, req)
				return
			}
			resp.Header.Del("X-Live")
		}
	}

	var body []byte

	if liveLength > 0 {

		var gzipSet bool
		var respBody io.ReadCloser

		// Check Content-Encoding to see if upstream sent gzipped content.
		if resp.Header.Get("Content-Encoding") == "gzip" {
			gzipSet = true
			respBody, err = gzip.NewReader(resp.Body)
			if err != nil {
				logging.Error("Error reading gzipped response from upstream: %s", err)
				frontend.ServeError500(conn, originalHost, req)
				return
			}
			defer respBody.Close()
		} else {
			respBody = resp.Body
		}

		// Read the X-Live content from the response body.
		liveMessage := make([]byte, liveLength)
		n, err := respBody.Read(liveMessage)
		if n != liveLength || err != nil {
			logging.Error("Error reading X-Live response from upstream: %s", err)
			frontend.ServeError500(conn, originalHost, req)
			return
		}

		// Read the response to send back to the original request.
		body, err = ioutil.ReadAll(respBody)
		if err != nil {
			logging.Error("Error reading non X-Live response from upstream: %s", err)
			frontend.ServeError500(conn, originalHost, req)
			return
		}

		// Re-encode the response if it had been gzipped by upstream.
		if gzipSet {
			buffer := &bytes.Buffer{}
			encoder, err := gzip.NewWriter(buffer)
			if err != nil {
				logging.Error("Error creating a new gzip Writer: %s", err)
				frontend.ServeError500(conn, originalHost, req)
				return
			}
			n, err = encoder.Write(body)
			if n != len(body) || err != nil {
				logging.Error("Error writing to the gzip Writer: %s", err)
				frontend.ServeError500(conn, originalHost, req)
				return
			}
			err = encoder.Close()
			if err != nil {
				logging.Error("Error finalising the write to the gzip Writer: %s", err)
				frontend.ServeError500(conn, originalHost, req)
				return
			}
			body = buffer.Bytes()
		}

		resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(body)))
		liveChannel <- liveMessage

	} else {
		// Read the full response body.
		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			logging.Error("Error reading response from upstream: %s", err)
			frontend.ServeError502(conn, originalHost, req)
			return
		}
	}

	// Set the received headers back to the initial connection.
	for k, values := range resp.Header {
		for _, v := range values {
			headers.Add(k, v)
		}
	}

	// Write the response body back to the initial connection.
	conn.WriteHeader(resp.StatusCode)
	conn.Write(body)
	frontend.Log(HTTPS_UPSTREAM, resp.StatusCode, originalHost, req)

}
Beispiel #16
0
func (s Session) perform(method, url, data string) {
	var req http.Request
	req.URL, _ = http.ParseURL(url)
	req.Method = method
	req.Header = s.headers
	req.ContentLength = int64(len(data))
	req.Body = myCloser{bytes.NewBufferString(data)}
	if *verbose {
		req.Write(os.Stderr)
	}
	retry := 0
request:
	req.Body = myCloser{bytes.NewBufferString(data)} // recreate anew, in case of retry
	err := s.conn.Write(&req)
	if err != nil {
		if retry < 2 {
			if err == io.ErrUnexpectedEOF {
				// the underlying connection has been closed "gracefully"
				retry++
				s.conn.Close()
				s.conn = dial(s.host)
				goto request
			} else if protoerr, ok := err.(*http.ProtocolError); ok && protoerr == http.ErrPersistEOF {
				// the connection has been closed in an HTTP keepalive sense
				retry++
				s.conn.Close()
				s.conn = dial(s.host)
				goto request
			}
		}
		fmt.Fprintln(os.Stderr, "http-gonsole: could not send request:", err)
		os.Exit(1)
	}
	r, err := s.conn.Read(&req)
	if err != nil {
		if protoerr, ok := err.(*http.ProtocolError); ok && protoerr == http.ErrPersistEOF {
			// the remote requested that this be the last request serviced,
			// we proceed as the response is still valid
			defer s.conn.Close()
			defer func() { s.conn = dial(s.host) }()
			goto output
		}
		fmt.Fprintln(os.Stderr, "http-gonsole: could not read response:", err)
		os.Exit(1)
	}
output:
	if len(data) > 0 {
		fmt.Println()
	}
	if r.StatusCode >= 500 {
		fmt.Printf(colorize(C_5xx, "%s %s\n"), r.Proto, r.Status)
	} else if r.StatusCode >= 400 {
		fmt.Printf(colorize(C_4xx, "%s %s\n"), r.Proto, r.Status)
	} else if r.StatusCode >= 300 {
		fmt.Printf(colorize(C_3xx, "%s %s\n"), r.Proto, r.Status)
	} else if r.StatusCode >= 200 {
		fmt.Printf(colorize(C_2xx, "%s %s\n"), r.Proto, r.Status)
	}
	if len(r.Header) > 0 {
		for key, arr := range r.Header {
			for _, val := range arr {
				fmt.Printf(colorize(C_Header, "%s: "), key)
				fmt.Println(val)
			}
		}
		fmt.Println()
	}
	if *rememberCookies {
		if cookies, found := r.Header["Set-Cookie"]; found {
			for _, h := range cookies {
				cookie := new(Cookie)
				cookie.Items = map[string]string{}
				re, _ := regexp.Compile("^[^=]+=[^;]+(; *(expires=[^;]+|path=[^;,]+|domain=[^;,]+|secure))*,?")
				rs := re.FindAllString(h, -1)
				for _, ss := range rs {
					m := strings.Split(ss, ";", -1)
					for _, n := range m {
						t := strings.Split(n, "=", 2)
						if len(t) == 2 {
							t[0] = strings.Trim(t[0], " ")
							t[1] = strings.Trim(t[1], " ")
							switch t[0] {
							case "domain":
								cookie.domain = t[1]
							case "path":
								cookie.path = t[1]
							case "expires":
								tm, err := time.Parse("Fri, 02-Jan-2006 15:04:05 MST", t[1])
								if err != nil {
									tm, err = time.Parse("Fri, 02-Jan-2006 15:04:05 -0700", t[1])
								}
								cookie.expires = tm
							case "secure":
								cookie.secure = true
							case "HttpOnly":
								cookie.httpOnly = true
							default:
								cookie.Items[t[0]] = t[1]
							}
						}
					}
				}
				*s.cookies = append(*s.cookies, cookie)
			}
		}
	}
	h := r.Header.Get("Content-Length")
	if len(h) > 0 {
		n, _ := strconv.Atoi64(h)
		b := make([]byte, n)
		io.ReadFull(r.Body, b)
		fmt.Println(string(b))
	} else if method != "HEAD" {
		b, _ := ioutil.ReadAll(r.Body)
		fmt.Println(string(b))
	} else {
		// TODO: streaming?
	}
}