mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vlib.http: fix http schannel & follow redirects & cleanup
This commit is contained in:

committed by
Alexander Medvednikov

parent
2ebfc8ab73
commit
a0b59783a2
@@ -31,7 +31,7 @@ fn init_module() {
|
||||
//C.OPENSSL_config(0)
|
||||
}
|
||||
|
||||
fn ssl_do(method, host_name, path string) string {
|
||||
fn ssl_do(method, host_name, path string) Response {
|
||||
//ssl_method := C.SSLv23_method()
|
||||
ssl_method := C.TLSv1_2_method()
|
||||
if isnil(method) {
|
||||
@@ -66,10 +66,8 @@ fn ssl_do(method, host_name, path string) string {
|
||||
res = C.BIO_do_handshake(web)
|
||||
cert := C.SSL_get_peer_certificate(ssl)
|
||||
res = C.SSL_get_verify_result(ssl)
|
||||
///////
|
||||
s := '$method $path HTTP/1.1\r\n' +
|
||||
'Host: $host_name\r\n' +
|
||||
'Connection: close\r\n\r\n'
|
||||
///////
|
||||
s := build_request_headers('', method, host_name, path)
|
||||
C.BIO_puts(web, s.str)
|
||||
C.BIO_puts(out, '\n')
|
||||
mut sb := strings.new_builder(100)
|
||||
@@ -91,6 +89,7 @@ fn ssl_do(method, host_name, path string) string {
|
||||
}
|
||||
if !isnil(ctx) {
|
||||
C.SSL_CTX_free(ctx)
|
||||
}
|
||||
return sb.str()
|
||||
}
|
||||
|
||||
return parse_response(sb.str() )
|
||||
}
|
||||
|
@@ -4,28 +4,44 @@
|
||||
|
||||
module http
|
||||
|
||||
import strings
|
||||
import strings
|
||||
import net.urllib
|
||||
|
||||
|
||||
#flag windows -I @VROOT/thirdparty/vschannel
|
||||
#flag -lws2_32 -lcrypt32
|
||||
#flag -l ws2_32
|
||||
#flag -l crypt32
|
||||
|
||||
#include "vschannel.c"
|
||||
|
||||
const (
|
||||
max_redirects = 4
|
||||
)
|
||||
|
||||
fn init_module() {}
|
||||
|
||||
fn ssl_do(method, host_name, path string) string {
|
||||
mut buff := malloc(10000)
|
||||
fn ssl_do(method, host_name, path string) Response {
|
||||
C.vschannel_init()
|
||||
// TODO: joe-c
|
||||
// dynamically increase in vschannel.c if needed
|
||||
mut buff := malloc(44000)
|
||||
|
||||
req := '$method $path HTTP/1.0\r\nUser-Agent: v\r\nAccept:*/*\r\n\r\n'
|
||||
length := int(C.request(host_name.str, req.str, buff))
|
||||
mut p := if path == '' { '/' } else { path }
|
||||
mut req := build_request_headers('', method, host_name, p)
|
||||
mut length := int(C.request(host_name.str, req.str, buff))
|
||||
mut resp := parse_response(string(buff, length))
|
||||
|
||||
if length == 0 {
|
||||
return ''
|
||||
mut no_redirects := 0
|
||||
for resp.status_code == 301 && no_redirects <= max_redirects {
|
||||
u := urllib.parse(resp.headers['Location']) or { break }
|
||||
p = if u.path == '' { '/' } else { u.path }
|
||||
req = build_request_headers('', method, u.hostname(), p)
|
||||
length = int(C.request(u.hostname().str, req.str, buff))
|
||||
resp = parse_response(string(buff, length))
|
||||
no_redirects++
|
||||
}
|
||||
|
||||
resp := tos(buff, length)
|
||||
|
||||
free(buff)
|
||||
C.vschannel_cleanup()
|
||||
return resp
|
||||
}
|
||||
|
@@ -93,7 +93,6 @@ pub fn (req mut Request) add_header(key, val string) {
|
||||
}
|
||||
|
||||
pub fn (req &Request) do() Response {
|
||||
mut headers := map[string]string{}
|
||||
if req.typ == 'POST' {
|
||||
// req.headers << 'Content-Type: application/x-www-form-urlencoded'
|
||||
}
|
||||
@@ -108,9 +107,13 @@ pub fn (req &Request) do() Response {
|
||||
if !is_ssl {
|
||||
panic('non https requests are not supported right now')
|
||||
}
|
||||
s := ssl_do(req.typ, url.host, url.path)
|
||||
// s := ssl_do(req.typ, url.host, url.path)
|
||||
first_header := s.all_before('\n')
|
||||
|
||||
return ssl_do(req.typ, url.hostname(), url.path)
|
||||
}
|
||||
|
||||
fn parse_response(resp string) Response {
|
||||
mut headers := map[string]string{}
|
||||
first_header := resp.all_before('\n')
|
||||
mut status_code := 0
|
||||
if first_header.contains('HTTP/') {
|
||||
val := first_header.find_between(' ', ' ')
|
||||
@@ -122,14 +125,14 @@ pub fn (req &Request) do() Response {
|
||||
mut i := 1
|
||||
for {
|
||||
old_pos := nl_pos
|
||||
nl_pos = s.index_after('\n', nl_pos+1)
|
||||
nl_pos = resp.index_after('\n', nl_pos+1)
|
||||
if nl_pos == -1 {
|
||||
break
|
||||
}
|
||||
h := s.substr(old_pos + 1, nl_pos)
|
||||
h := resp.substr(old_pos + 1, nl_pos)
|
||||
// End of headers
|
||||
if h.len <= 1 {
|
||||
text = s.right(nl_pos + 1)
|
||||
text = resp.right(nl_pos + 1)
|
||||
break
|
||||
}
|
||||
i++
|
||||
@@ -144,14 +147,24 @@ pub fn (req &Request) do() Response {
|
||||
val := h.right(pos + 2)
|
||||
headers[key] = val.trim_space()
|
||||
}
|
||||
|
||||
if headers['Transfer-Encoding'] == 'chunked' {
|
||||
text = chunked.decode( text )
|
||||
}
|
||||
|
||||
return Response {
|
||||
status_code: status_code
|
||||
headers: headers
|
||||
text: text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_request_headers(user_agent, method, host_name, path string) string {
|
||||
ua := if user_agent == '' { 'v' } else { user_agent }
|
||||
return '$method $path HTTP/1.1\r\n' +
|
||||
'Host: $host_name\r\n' +
|
||||
'User-Agent: $ua\r\n' +
|
||||
'Connection: close\r\n\r\n'
|
||||
}
|
||||
|
||||
pub fn unescape_url(s string) string {
|
||||
|
Reference in New Issue
Block a user