func (curl *CURL) Recv(buffer []byte) (int, error) {
	p := curl.handle
	buflen := len(buffer)
	buf := C.CString(string(buffer))
	n := C.size_t(0)
	ret := C.curl_easy_recv(p, unsafe.Pointer(buf), C.size_t(buflen), &n)
	return copy(buffer, C.GoStringN(buf, C.int(n))), newCurlError(ret)
}
curl_easy_recv - receives raw data on an "easy" connection
package curl
import "C"
import (
	"fmt"
	"mime"
	"path"
	"unsafe"
	"sync"
)
type CurlInfo C.CURLINFO
type CurlError C.CURLcode
type CurlString *C.char
func NewCurlString(s string) CurlString {
	return CurlString(unsafe.Pointer(C.CString(s)))
}
func FreeCurlString(s CurlString) {
	C.free(unsafe.Pointer(s))
}
func (e CurlError) Error() string {
	ret := C.curl_easy_strerror(C.CURLcode(e))
	return fmt.Sprintf("curl: %s", C.GoString(ret))
}
func newCurlError(errno C.CURLcode) error {
	if errno == C.CURLE_OK {  
		return nil
	}
	return CurlError(errno)
}
type CURL struct {
	handle unsafe.Pointer
	headerFunction, writeFunction *func([]byte, interface{}) bool
	readFunction                  *func([]byte, interface{}) int  
	progressFunction              *func(float64, float64, float64, float64, interface{}) bool
	fnmatchFunction               *func(string, string, interface{}) int
	headerData, writeData, readData, progressData, fnmatchData interface{}
	mallocAllocs []*C.char
}
type contextMap struct {
	items map[uintptr]*CURL
	sync.RWMutex
}
func (c *contextMap) Set(k uintptr, v *CURL) {
	c.Lock()
	defer c.Unlock()
	c.items[k] = v
}
func (c *contextMap) Get(k uintptr) *CURL {
	c.RLock()
	defer c.RUnlock()
	return c.items[k]
}
func (c *contextMap) Delete(k uintptr) {
	c.Lock()
	defer c.Unlock()
	delete(c.items, k)
}
var context_map = &contextMap {
	items: make(map[uintptr]*CURL),
}
func EasyInit() *CURL {
	p := C.curl_easy_init()
	c := &CURL{handle: p, mallocAllocs: make([]*C.char, 0)}  
	context_map.Set(uintptr(p), c)
	return c
}
func (curl *CURL) Duphandle() *CURL {
	p := C.curl_easy_duphandle(curl.handle)
	c := &CURL{handle: p}
	context_map.Set(uintptr(p), c)
	return c
}
func (curl *CURL) Cleanup() {
	p := curl.handle
	C.curl_easy_cleanup(p)
	curl.MallocFreeAfter(0)
	context_map.Delete(uintptr(p))
}
func (curl *CURL) Setopt(opt int, param interface{}) error {
	p := curl.handle
	if param == nil {
		return newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), nil))
	}
	switch {
	case opt == OPT_READDATA:  
		curl.readData = param
		return nil
	case opt == OPT_PROGRESSDATA:
		curl.progressData = param
		return nil
	case opt == OPT_HEADERDATA:  
		curl.headerData = param
		return nil
	case opt == OPT_WRITEDATA:  
		curl.writeData = param
		return nil
	case opt == OPT_READFUNCTION:
		fun := param.(func([]byte, interface{}) int)
		curl.readFunction = &fun
		ptr := C.return_read_function()
		if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
			return newCurlError(C.curl_easy_setopt_pointer(p, OPT_READDATA, unsafe.Pointer(curl.handle)))
		} else {
			return err
		}
	case opt == OPT_PROGRESSFUNCTION:
		fun := param.(func(float64, float64, float64, float64, interface{}) bool)
		curl.progressFunction = &fun
		ptr := C.return_progress_function()
		if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
			return newCurlError(C.curl_easy_setopt_pointer(p, OPT_PROGRESSDATA, unsafe.Pointer(curl.handle)))
		} else {
			return err
		}
	case opt == OPT_HEADERFUNCTION:
		fun := param.(func([]byte, interface{}) bool)
		curl.headerFunction = &fun
		ptr := C.return_header_function()
		if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
			return newCurlError(C.curl_easy_setopt_pointer(p, OPT_HEADERDATA, unsafe.Pointer(curl.handle)))
		} else {
			return err
		}
	case opt == OPT_WRITEFUNCTION:
		fun := param.(func([]byte, interface{}) bool)
		curl.writeFunction = &fun
		ptr := C.return_write_function()
		if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
			return newCurlError(C.curl_easy_setopt_pointer(p, OPT_WRITEDATA, unsafe.Pointer(curl.handle)))
		} else {
			return err
		}
	case opt == OPT_HTTPPOST:
		post := param.(*Form)
		ptr := post.head
		return newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), unsafe.Pointer(ptr)))
	case opt >= C.CURLOPTTYPE_OFF_T:
		val := C.off_t(0)
		switch t := param.(type) {
		case int:
			val = C.off_t(t)
		case uint64:
			val = C.off_t(t)
		default:
			panic("OFF_T conversion not supported")
		}
		return newCurlError(C.curl_easy_setopt_off_t(p, C.CURLoption(opt), val))
	case opt >= C.CURLOPTTYPE_FUNCTIONPOINT:
		panic("function pointer not implemented yet!")
	case opt >= C.CURLOPTTYPE_OBJECTPOINT:
		switch t := param.(type) {
		case string:
			ptr := C.CString(t)
			curl.mallocAddPtr(ptr)
			return newCurlError(C.curl_easy_setopt_string(p, C.CURLoption(opt), ptr))
		case CurlString:
			ptr := (*C.char)(t)
			return newCurlError(C.curl_easy_setopt_string(p, C.CURLoption(opt), ptr))
		case []string:
			if len(t) > 0 {
				ptr := C.CString(t[0])
				curl.mallocAddPtr(ptr)
				a_slist := C.curl_slist_append(nil, ptr)
				for _, s := range t[1:] {
					ptr := C.CString(s)
					curl.mallocAddPtr(ptr)
					a_slist = C.curl_slist_append(a_slist, ptr)
				}
				return newCurlError(C.curl_easy_setopt_slist(p, C.CURLoption(opt), a_slist))
			} else {
				return newCurlError(C.curl_easy_setopt_slist(p, C.CURLoption(opt), nil))
			}
		case []CurlString:
			if len(t) > 0 {
				ptr := (*C.char)(t[0])
				a_slist := C.curl_slist_append(nil, ptr)
				for _, s := range t[1:] {
					ptr := (*C.char)(s)
					a_slist = C.curl_slist_append(a_slist, ptr)
				}
				return newCurlError(C.curl_easy_setopt_slist(p, C.CURLoption(opt), a_slist))
			} else {
				return newCurlError(C.curl_easy_setopt_slist(p, C.CURLoption(opt), nil))
			}
		default:
			return newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt),
				unsafe.Pointer(&param)))
		}
	case opt >= C.CURLOPTTYPE_LONG:
		val := C.long(0)
		switch t := param.(type) {
		case int:
			val = C.long(t)
		case bool:
			if t {
				val = 1
			}
		case int64:
			val = C.long(t)
		case int32:
			val = C.long(t)
		default:
			panic("not supported converstion to c long")
		}
		return newCurlError(C.curl_easy_setopt_long(p, C.CURLoption(opt), val))
	}
	panic("opt param error!")
}
func (curl *CURL) Send(buffer []byte) (int, error) {
	p := curl.handle
	buflen := len(buffer)
	n := C.size_t(0)
	ret := C.curl_easy_send(p, unsafe.Pointer(&buffer[0]), C.size_t(buflen), &n)
	return int(n), newCurlError(ret)
}