http: follow redirects (openssl & schannel) + fix url params

pull/1633/head
joe-conigliaro 2019-08-17 22:50:47 +10:00 committed by Alexander Medvednikov
parent a4e648627e
commit 56566ba3d0
3 changed files with 31 additions and 26 deletions

View File

@ -93,5 +93,5 @@ fn ssl_do(method, host_name, path string) Response {
C.SSL_CTX_free(ctx) C.SSL_CTX_free(ctx)
} }
return parse_response(sb.str() ) return parse_response(sb.str())
} }

View File

@ -14,10 +14,6 @@ import net.urllib
#include "vschannel.c" #include "vschannel.c"
const (
max_redirects = 4
)
fn init_module() {} fn init_module() {}
fn ssl_do(method, host_name, path string) Response { fn ssl_do(method, host_name, path string) Response {
@ -26,22 +22,9 @@ fn ssl_do(method, host_name, path string) Response {
// dynamically increase in vschannel.c if needed // dynamically increase in vschannel.c if needed
mut buff := malloc(44000) mut buff := malloc(44000)
mut p := if path == '' { '/' } else { path } p := if path == '' { '/' } else { path }
mut req := build_request_headers('', method, host_name, p) req := build_request_headers('', method, host_name, p)
mut length := int(C.request(host_name.str, req.str, buff)) length := int(C.request(host_name.str, req.str, buff))
mut resp := parse_response(string(buff, length))
mut no_redirects := 0 return parse_response(string(buff, length))
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++
}
free(buff)
C.vschannel_cleanup()
return resp
} }

View File

@ -7,6 +7,10 @@ module http
import net.urllib import net.urllib
import http.chunked import http.chunked
const (
max_redirects = 4
)
struct Request { struct Request {
pub: pub:
headers2 []string headers2 []string
@ -100,15 +104,33 @@ pub fn (req &Request) do() Response {
//h := '$key: $val' //h := '$key: $val'
} }
url := urllib.parse(req.url) or { url := urllib.parse(req.url) or {
// panic('http.request.do: invalid URL $req.url' panic('http.request.do: invalid URL $req.url')
return Response{} //error('ff')} // return Response{} //error('ff')}
} }
is_ssl := url.scheme == 'https' is_ssl := url.scheme == 'https'
if !is_ssl { if !is_ssl {
panic('non https requests are not supported right now') panic('non https requests are not supported right now')
} }
return ssl_do(req.typ, url.hostname(), url.path) // first request
mut u := if url.query().size > 0 { '$url.path?${url.query().encode()}' } else { url.path }
mut resp := ssl_do(req.typ, url.hostname(), u)
// follow any redirects
mut no_redirects := 0
for resp.status_code in [301, 302, 303, 307 ,308] {
if no_redirects == max_redirects {
panic('http.request.do: maximum number of redirects reached ($max_redirects)')
}
h_loc := resp.headers['Location']
r_url := urllib.parse(h_loc) or {
panic('http.request.do: cannot follow redirect, location header has invalid url $h_loc')
}
u = if r_url.query().size > 0 { '$r_url.path?${r_url.query().encode()}' } else { r_url.path }
resp = ssl_do(req.typ, r_url.hostname(), u)
no_redirects++
}
return resp
} }
fn parse_response(resp string) Response { fn parse_response(resp string) Response {