206 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			V
		
	
	
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
 | 
						||
// Use of this source code is governed by an MIT license
 | 
						||
// that can be found in the LICENSE file.
 | 
						||
 | 
						||
module http
 | 
						||
 | 
						||
#include <curl/curl.h>
 | 
						||
#flag darwin -lcurl
 | 
						||
#flag windows -lcurl
 | 
						||
#flag linux -lcurl
 | 
						||
 | 
						||
fn C.curl_easy_init() *C.CURL 
 | 
						||
 | 
						||
fn foo() {} 
 | 
						||
 | 
						||
type wsfn fn (s string, ptr voidptr)
 | 
						||
 | 
						||
struct MemoryStruct {
 | 
						||
	size     size_t
 | 
						||
	ws_func  wsfn
 | 
						||
	user_ptr voidptr // for wsfn
 | 
						||
	strings  []string
 | 
						||
}
 | 
						||
 | 
						||
import const (
 | 
						||
	CURLOPT_WRITEFUNCTION
 | 
						||
	CURLOPT_SSL_VERIFYPEER
 | 
						||
	CURLOPT_HEADERFUNCTION
 | 
						||
	CURLOPT_WRITEDATA
 | 
						||
	CURLOPT_HEADERDATA
 | 
						||
	CURLOPT_FOLLOWLOCATION
 | 
						||
	CURLOPT_URL
 | 
						||
	CURLOPT_VERBOSE
 | 
						||
	CURLOPT_HTTP_VERSION
 | 
						||
	CURL_HTTP_VERSION_1_1
 | 
						||
	CURLOPT_HTTPHEADER
 | 
						||
	CURLOPT_POSTFIELDS
 | 
						||
	CURLOPT_CUSTOMREQUEST
 | 
						||
	CURLOPT_TCP_KEEPALIVE
 | 
						||
	CURLINFO_CONTENT_LENGTH_DOWNLOAD 
 | 
						||
	CURLE_OK
 | 
						||
)
 | 
						||
 | 
						||
fn C.curl_easy_strerror(curl voidptr) byteptr
 | 
						||
 | 
						||
fn C.curl_easy_perform(curl voidptr) C.CURLcode
 | 
						||
 | 
						||
fn write_fn(contents byteptr, size, nmemb int, _mem *MemoryStruct) int {
 | 
						||
	mut mem := _mem
 | 
						||
	// # printf("size =%d nmemb=%d contents=%s\n", size, nmemb, contents);
 | 
						||
	realsize := size * nmemb// TODO size_t ?
 | 
						||
	// if !isnil(mem.ws_func) {
 | 
						||
	# if (mem->ws_func)
 | 
						||
	{
 | 
						||
		//C.printf('\n\nhttp_mac.m: GOT WS FUNC. size=%d\n', realsize)
 | 
						||
		// Skip negative and 0 junk chars in the WS string
 | 
						||
		mut start := 0
 | 
						||
		for i := 0; i < realsize; i++ {
 | 
						||
			// printf("char=%d %c\n", s[i], s[i]);
 | 
						||
			if contents[i] == 0 && start == 0 {
 | 
						||
				start = i
 | 
						||
				break
 | 
						||
			}
 | 
						||
		}
 | 
						||
		contents += start + 1
 | 
						||
		// printf("GOOD CONTEnTS=%s\n", contents);
 | 
						||
		s := string(contents)
 | 
						||
		// mem.ws_func('kek', 0)
 | 
						||
		# mem->ws_func(s, mem->user_ptr);
 | 
						||
	}
 | 
						||
	mut c := string(contents)
 | 
						||
	c = c.trim_space()
 | 
						||
	// Need to clone because libcurl reuses this memory
 | 
						||
	mem.strings << c.clone()
 | 
						||
	return realsize
 | 
						||
}
 | 
						||
 | 
						||
struct C.curl_slist { }
 | 
						||
 | 
						||
pub fn (req &Request) do() Response {
 | 
						||
	//println('req.do() mac/linux url="$req.url" data="$req.data"')
 | 
						||
	// println('req.do() url="$req.url"')
 | 
						||
	/* 
 | 
						||
	mut resp := Response {
 | 
						||
		headers: map[string]string{}
 | 
						||
	}
 | 
						||
*/
 | 
						||
	mut headers := map[string]string{}
 | 
						||
	// no data at this point
 | 
						||
	chunk := MemoryStruct {
 | 
						||
		ws_func: req.ws_func
 | 
						||
		user_ptr: req.user_ptr
 | 
						||
	}
 | 
						||
	// header chunk
 | 
						||
	hchunk := MemoryStruct {
 | 
						||
		ws_func: foo 
 | 
						||
		user_ptr: 0
 | 
						||
	}
 | 
						||
	// init curl
 | 
						||
	curl := C.curl_easy_init()
 | 
						||
	if isnil(curl) {
 | 
						||
		println('curl init failed')
 | 
						||
		return Response{}
 | 
						||
	}
 | 
						||
	// options
 | 
						||
	// url2 := req.url.clone()
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_URL, req.url.cstr())// ..clone())
 | 
						||
	// C.curl_easy_setopt(curl, CURLOPT_URL, 'http://example.com')
 | 
						||
	// return resp
 | 
						||
	// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
 | 
						||
	$if windows {
 | 
						||
		C.curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0)
 | 
						||
	}
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn)
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_fn)
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk)
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_HEADERDATA, &hchunk)
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1)
 | 
						||
	if req.typ == 'POST' {
 | 
						||
		C.curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req.data.cstr())
 | 
						||
		C.curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, 'POST')
 | 
						||
		// req.headers << 'Content-Type: application/x-www-form-urlencoded'
 | 
						||
	}
 | 
						||
	// Add request headers
 | 
						||
	mut hlist := &C.curl_slist{!}
 | 
						||
	// for i, h := range req.headers {
 | 
						||
	for key, val in req.headers {
 | 
						||
		h := '$key: $val'
 | 
						||
		hlist = C.curl_slist_append(hlist, h.cstr())
 | 
						||
	}
 | 
						||
	// curl_easy_setopt(curl, CURLOPT_HTTP_VERSION,	// (long)CURL_HTTP_VERSION_2TLS);<3B>`C<>ʀ9<CA80>
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1)
 | 
						||
	if req.verbose {
 | 
						||
		C.curl_easy_setopt(curl, CURLOPT_VERBOSE, 1)
 | 
						||
	}
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hlist)
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1)
 | 
						||
	C.curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1)
 | 
						||
	//println('bef easy()')
 | 
						||
	res := C.curl_easy_perform(curl)
 | 
						||
	//println('after easy()')
 | 
						||
	# if (res != CURLE_OK )
 | 
						||
	{
 | 
						||
		err := C.curl_easy_strerror(res)
 | 
						||
		println('curl_easy_perform() failed: $err')
 | 
						||
	}
 | 
						||
	body := chunk.strings.join('')// string(chunk.memory)
 | 
						||
	// chunk.strings.free()
 | 
						||
	// resp.headers = hchunk.strings
 | 
						||
	if hchunk.strings.len == 0 {
 | 
						||
		return Response{}
 | 
						||
	}
 | 
						||
	first_header := hchunk.strings.first()
 | 
						||
	mut status_code := 0
 | 
						||
	if first_header.contains('HTTP/') {
 | 
						||
		val := first_header.find_between(' ', ' ')
 | 
						||
		status_code = val.int()
 | 
						||
	}
 | 
						||
	// Build resp headers map
 | 
						||
	// println('building resp headers hchunk.strings.len')
 | 
						||
	for h in hchunk.strings {
 | 
						||
		// break
 | 
						||
		// println(h)
 | 
						||
		vals := h.split(':')
 | 
						||
		pos := h.index(':')
 | 
						||
		if pos == -1 {
 | 
						||
			continue
 | 
						||
		}
 | 
						||
		if h.contains('Content-Type') {
 | 
						||
			continue
 | 
						||
		}
 | 
						||
		key := h.left(pos)
 | 
						||
		val := h.right(pos + 1)
 | 
						||
		// println('"$key" *** "$val"')
 | 
						||
		// val2 := val.trim_space()
 | 
						||
		// println('val2="$val2"')
 | 
						||
		headers[key] = val// val.trim_space()
 | 
						||
	}
 | 
						||
	// println('done')
 | 
						||
	// j.println(resp.status_code)
 | 
						||
	// println('body=')
 | 
						||
	// j.println(resp.body)
 | 
						||
	// j.println('headers=')
 | 
						||
	// j.println(hchunk.strings)
 | 
						||
	C.curl_easy_cleanup(curl)
 | 
						||
	//println('end of req.do() url="$req.url"')
 | 
						||
	return Response {
 | 
						||
		body: body
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
fn unescape(s string) string {
 | 
						||
	return string(byteptr(C.curl_unescape(s.cstr(), s.len)))
 | 
						||
}
 | 
						||
 | 
						||
fn escape(s string) string {
 | 
						||
	return string(byteptr(C.curl_escape(s.cstr(), s.len)))
 | 
						||
}
 | 
						||
 | 
						||
// ////////////////
 | 
						||
fn (req &Request) do2() Response {
 | 
						||
	mut resp := Response{}
 | 
						||
	return resp
 | 
						||
}
 | 
						||
 |