func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
	var req *http.Request
	var resp *http.Response
	var httpPath string
	var err error
	var respBody []byte
	var numReqs = 1
	checkRetry := c.CheckRetry
	if checkRetry == nil {
		checkRetry = DefaultCheckRetry
	}
	cancelled := make(chan bool, 1)
	reqLock := new(sync.Mutex)
	if rr.Cancel != nil {
		cancelRoutine := make(chan bool)
		defer close(cancelRoutine)
		go func() {
			select {
			case <-rr.Cancel:
				cancelled <- true
				logger.Debug("send.request is cancelled")
			case <-cancelRoutine:
				return
			}
			for {
				reqLock.Lock()
				c.httpClient.Transport.(*http.Transport).CancelRequest(req)
				reqLock.Unlock()
				select {
				case <-time.After(100 * time.Millisecond):
				case <-cancelRoutine:
					return
				}
			}
		}()
	}
	sleep := 25 * time.Millisecond
	maxSleep := time.Second
	for attempt := 0; ; attempt++ {
		if attempt > 0 {
			select {
			case <-cancelled:
				return nil, ErrRequestCancelled
			case <-time.After(sleep):
				sleep = sleep * 2
				if sleep > maxSleep {
					sleep = maxSleep
				}
			}
		}
		logger.Debug("Connecting to etcd: attempt", attempt+1, "for", rr.RelativePath)
		if rr.Method == "GET" && c.config.Consistency == WEAK_CONSISTENCY {
			httpPath = c.getHttpPath(true, rr.RelativePath)
		} else {
			httpPath = c.getHttpPath(false, rr.RelativePath)
		}
		if c.cURLch != nil {
			command := fmt.Sprintf("curl -X %s %s", rr.Method, httpPath)
			for key, value := range rr.Values {
				command += fmt.Sprintf(" -d %s=%s", key, value[0])
			}
			c.sendCURL(command)
		}
		logger.Debug("send.request.to ", httpPath, " | method ", rr.Method)
		reqLock.Lock()
		if rr.Values == nil {
			if req, err = http.NewRequest(rr.Method, httpPath, nil); err != nil {
				return nil, err
			}
		} else {
			body := strings.NewReader(rr.Values.Encode())
			if req, err = http.NewRequest(rr.Method, httpPath, body); err != nil {
				return nil, err
			}
			req.Header.Set("Content-Type",
				"application/x-www-form-urlencoded; param=value")
		}
		reqLock.Unlock()
		resp, err = c.httpClient.Do(req)
		defer func() {
			if resp != nil {
				resp.Body.Close()
			}
		}()
		select {
		case <-cancelled:
			return nil, ErrRequestCancelled
		default:
		}
		numReqs++
		if err != nil {
			logger.Debug("network error:", err.Error())
			lastResp := http.Response{}
			if checkErr := checkRetry(c.cluster, numReqs, lastResp, err); checkErr != nil {
				return nil, checkErr
			}
			c.cluster.switchLeader(attempt % len(c.cluster.Machines))
			continue
		}
		logger.Debug("recv.response.from", httpPath)
		if validHttpStatusCode[resp.StatusCode] {
			respBody, err = ioutil.ReadAll(resp.Body)
			if err == nil {
				logger.Debug("recv.success.", httpPath)
				break
			}
			select {
			case <-cancelled:
				return nil, ErrRequestCancelled
			default:
			}
		}
		if resp.StatusCode == http.StatusTemporaryRedirect {
			u, err := resp.Location()
			if err != nil {
				logger.Warning(err)
			} else {
				c.cluster.updateLeaderFromURL(u)
				logger.Debug("recv.response.relocate", u.String())
			}
			resp.Body.Close()
			continue
		}
		if checkErr := checkRetry(c.cluster, numReqs, *resp,
			errors.New("Unexpected HTTP status code")); checkErr != nil {
			return nil, checkErr
		}
		resp.Body.Close()
	}
	r := &RawResponse{
		StatusCode: resp.StatusCode,
		Body:       respBody,
		Header:     resp.Header,
	}
	return r, nil
}
SendRequest sends a HTTP request and returns a Response as defined by etcd
package etcd
import (
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"path"
	"strings"
	"sync"
	"time"
)
var (
	ErrRequestCancelled = errors.New("sending request is cancelled")
)
type RawRequest struct {
	Method       string
	RelativePath string
	Values       url.Values
	Cancel       <-chan bool
}
func NewRawRequest(method, relativePath string, values url.Values, cancel <-chan bool) *RawRequest {
	return &RawRequest{
		Method:       method,
		RelativePath: relativePath,
		Values:       values,
		Cancel:       cancel,
	}
}
func (c *Client) getCancelable(key string, options Options,
	cancel <-chan bool) (*RawResponse, error) {
	logger.Debugf("get %s [%s]", key, c.cluster.Leader)
	p := keyToPath(key)
	if c.config.Consistency == STRONG_CONSISTENCY {
		options["consistent"] = true
	}
	str, err := options.toParameters(VALID_GET_OPTIONS)
	if err != nil {
		return nil, err
	}
	p += str
	req := NewRawRequest("GET", p, nil, cancel)
	resp, err := c.SendRequest(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}
func (c *Client) get(key string, options Options) (*RawResponse, error) {
	return c.getCancelable(key, options, nil)
}
func (c *Client) put(key string, value string, ttl uint64,
	options Options) (*RawResponse, error) {
	logger.Debugf("put %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.Leader)
	p := keyToPath(key)
	str, err := options.toParameters(VALID_PUT_OPTIONS)
	if err != nil {
		return nil, err
	}
	p += str
	req := NewRawRequest("PUT", p, buildValues(value, ttl), nil)
	resp, err := c.SendRequest(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}
func (c *Client) post(key string, value string, ttl uint64) (*RawResponse, error) {
	logger.Debugf("post %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.Leader)
	p := keyToPath(key)
	req := NewRawRequest("POST", p, buildValues(value, ttl), nil)
	resp, err := c.SendRequest(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}
func (c *Client) delete(key string, options Options) (*RawResponse, error) {
	logger.Debugf("delete %s [%s]", key, c.cluster.Leader)
	p := keyToPath(key)
	str, err := options.toParameters(VALID_DELETE_OPTIONS)
	if err != nil {
		return nil, err
	}
	p += str
	req := NewRawRequest("DELETE", p, nil, nil)
	resp, err := c.SendRequest(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}