2019-06-23 05:21:30 +03:00
|
|
|
|
// 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.
|
|
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
|
module http
|
|
|
|
|
|
|
|
|
|
#include <curl/curl.h>
|
|
|
|
|
#flag darwin -lcurl
|
|
|
|
|
#flag windows -lcurl
|
|
|
|
|
#flag linux -lcurl
|
2019-06-23 18:03:19 +03:00
|
|
|
|
|
|
|
|
|
fn C.curl_easy_init() *C.CURL
|
|
|
|
|
|
|
|
|
|
fn foo() {}
|
|
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
|
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
|
2019-06-24 00:02:11 +03:00
|
|
|
|
CURLINFO_CONTENT_LENGTH_DOWNLOAD
|
2019-06-22 21:20:28 +03:00
|
|
|
|
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 {
|
2019-06-28 16:24:46 +03:00
|
|
|
|
mut mem := _mem
|
2019-06-22 21:20:28 +03:00
|
|
|
|
// # 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)
|
|
|
|
|
{
|
2019-07-03 12:56:50 +03:00
|
|
|
|
//C.printf('\n\nhttp_mac.m: GOT WS FUNC. size=%d\n', realsize)
|
2019-06-22 21:20:28 +03:00
|
|
|
|
// 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);
|
2019-06-27 13:27:46 +03:00
|
|
|
|
s := string(contents)
|
2019-06-22 21:20:28 +03:00
|
|
|
|
// mem.ws_func('kek', 0)
|
|
|
|
|
# mem->ws_func(s, mem->user_ptr);
|
|
|
|
|
}
|
2019-06-27 13:27:46 +03:00
|
|
|
|
mut c := string(contents)
|
2019-06-22 21:20:28 +03:00
|
|
|
|
c = c.trim_space()
|
|
|
|
|
// Need to clone because libcurl reuses this memory
|
|
|
|
|
mem.strings << c.clone()
|
|
|
|
|
return realsize
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct C.curl_slist { }
|
|
|
|
|
|
|
|
|
|
fn (req &Request) do() Response {
|
2019-06-23 12:32:48 +03:00
|
|
|
|
//println('req.do() mac/linux url="$req.url" data="$req.data"')
|
2019-06-22 21:20:28 +03:00
|
|
|
|
// 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 {
|
2019-07-01 03:58:49 +03:00
|
|
|
|
ws_func: foo
|
2019-06-22 21:20:28 +03:00
|
|
|
|
user_ptr: 0
|
|
|
|
|
}
|
|
|
|
|
// init curl
|
|
|
|
|
curl := C.curl_easy_init()
|
|
|
|
|
if isnil(curl) {
|
2019-06-23 11:01:55 +03:00
|
|
|
|
println('curl init failed')
|
2019-06-22 21:20:28 +03:00
|
|
|
|
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 {
|
2019-07-14 23:26:21 +03:00
|
|
|
|
for key, val in req.headers {
|
2019-06-22 21:20:28 +03:00
|
|
|
|
h := '$key: $val'
|
|
|
|
|
hlist = C.curl_slist_append(hlist, h.cstr())
|
|
|
|
|
}
|
2019-06-23 05:21:30 +03:00
|
|
|
|
// curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, // (long)CURL_HTTP_VERSION_2TLS);<3B>`C<>ʀ9<CA80>
|
2019-06-22 21:20:28 +03:00
|
|
|
|
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)
|
2019-06-23 12:32:48 +03:00
|
|
|
|
//println('bef easy()')
|
2019-06-22 21:20:28 +03:00
|
|
|
|
res := C.curl_easy_perform(curl)
|
2019-06-23 12:32:48 +03:00
|
|
|
|
//println('after easy()')
|
2019-06-22 21:20:28 +03:00
|
|
|
|
# if (res != CURLE_OK )
|
|
|
|
|
{
|
|
|
|
|
err := C.curl_easy_strerror(res)
|
|
|
|
|
println('curl_easy_perform() failed: $err')
|
|
|
|
|
}
|
2019-06-27 13:27:46 +03:00
|
|
|
|
body := chunk.strings.join('')// string(chunk.memory)
|
2019-06-22 21:20:28 +03:00
|
|
|
|
// 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(' ', ' ')
|
2019-06-25 15:56:34 +03:00
|
|
|
|
status_code = val.int()
|
2019-06-22 21:20:28 +03:00
|
|
|
|
}
|
|
|
|
|
// 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)
|
2019-06-23 12:32:48 +03:00
|
|
|
|
//println('end of req.do() url="$req.url"')
|
2019-06-22 21:20:28 +03:00
|
|
|
|
return Response {
|
|
|
|
|
body: body
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn unescape(s string) string {
|
2019-06-27 13:27:46 +03:00
|
|
|
|
return string(byteptr(C.curl_unescape(s.cstr(), s.len)))
|
2019-06-22 21:20:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn escape(s string) string {
|
2019-06-27 13:27:46 +03:00
|
|
|
|
return string(byteptr(C.curl_escape(s.cstr(), s.len)))
|
2019-06-22 21:20:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ////////////////
|
|
|
|
|
fn (req &Request) do2() Response {
|
|
|
|
|
mut resp := Response{}
|
|
|
|
|
return resp
|
|
|
|
|
}
|
|
|
|
|
|