1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

run vfmt on http, net, sync, strconv

This commit is contained in:
Alexander Medvednikov
2019-12-22 01:41:42 +03:00
parent 28ecfb231d
commit 848cd3cb3e
18 changed files with 523 additions and 404 deletions

View File

@ -1,18 +1,15 @@
// 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
import strings
// On linux, prefer a localy build openssl, because it is
// much more likely for it to be newer, than the system
// openssl from libssl-dev. If there is no local openssl,
// the next flag is harmless, since it will still use the
// (older) system openssl.
#flag linux -I/usr/local/include/openssl -L/usr/local/lib
#flag -l ssl -l crypto
// MacPorts
#flag darwin -I/opt/local/include
@ -20,40 +17,74 @@ import strings
// Brew
#flag darwin -I/usr/local/opt/openssl/include
#flag darwin -L/usr/local/opt/openssl/lib
#include <openssl/ssl.h>
struct C.SSL {
}
fn C.SSL_library_init()
fn C.TLSv1_2_method() voidptr
fn C.SSL_CTX_set_options()
fn C.SSL_CTX_new() voidptr
fn C.SSL_CTX_set_verify_depth()
fn C.SSL_CTX_load_verify_locations() int
fn C.BIO_new_ssl_connect() voidptr
fn C.BIO_set_conn_hostname() int
fn C.BIO_get_ssl()
fn C.SSL_set_cipher_list() int
fn C.BIO_do_connect() int
fn C.BIO_do_handshake() int
fn C.SSL_get_peer_certificate() int
fn C.SSL_get_verify_result() int
fn C.SSL_set_tlsext_host_name() int
fn C.BIO_puts()
fn C.BIO_read()
fn C.BIO_free_all()
fn C.SSL_CTX_free()
fn init() int {
C.SSL_library_init()
return 1
}
fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response {
//ssl_method := C.SSLv23_method()
// ssl_method := C.SSLv23_method()
ssl_method := C.TLSv1_2_method()
if isnil(method) {
}
@ -89,13 +120,13 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response {
res = C.BIO_do_handshake(web)
C.SSL_get_peer_certificate(ssl)
res = C.SSL_get_verify_result(ssl)
///////
// /////
s := req.build_request_headers(method, host_name, path)
C.BIO_puts(web, s.str)
mut sb := strings.new_builder(100)
for {
buff := [1536]byte
len := int(C.BIO_read(web, buff, 1536) )
len := int(C.BIO_read(web, buff, 1536))
if len > 0 {
sb.write(tos(buff, len))
}
@ -109,6 +140,6 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response {
if !isnil(ctx) {
C.SSL_CTX_free(ctx)
}
return parse_response(sb.str())
}

View File

@ -1,27 +1,29 @@
module chunked
import strings
// See: https://en.wikipedia.org/wiki/Chunked_transfer_encoding
///////////////////////////////////////////////////////////////
// The chunk size is transferred as a hexadecimal number
// followed by \r\n as a line separator,
// /////////////////////////////////////////////////////////////
// The chunk size is transferred as a hexadecimal number
// followed by \r\n as a line separator,
// followed by a chunk of data of the given size.
// The end is marked with a chunk with size 0.
struct ChunkScanner {
mut:
pos int
pos int
text string
}
fn (s mut ChunkScanner) read_chunk_size() int {
mut n := 0
for {
if s.pos >= s.text.len { break }
if s.pos >= s.text.len {
break
}
c := s.text[s.pos]
if !c.is_hex_digit() { break }
n = n << 4
if !c.is_hex_digit() {
break
}
n = n<<4
n += int(unhex(c))
s.pos++
}
@ -29,9 +31,15 @@ fn (s mut ChunkScanner) read_chunk_size() int {
}
fn unhex(c byte) byte {
if `0` <= c && c <= `9` { return c - `0` }
else if `a` <= c && c <= `f` { return c - `a` + 10 }
else if `A` <= c && c <= `F` { return c - `A` + 10 }
if `0` <= c && c <= `9` {
return c - `0`
}
else if `a` <= c && c <= `f` {
return c - `a` + 10
}
else if `A` <= c && c <= `F` {
return c - `A` + 10
}
return 0
}
@ -47,17 +55,20 @@ fn (s mut ChunkScanner) read_chunk(chunksize int) string {
pub fn decode(text string) string {
mut sb := strings.new_builder(100)
mut cscanner := ChunkScanner {
mut cscanner := ChunkScanner{
pos: 0
text: text
}
for {
csize := cscanner.read_chunk_size()
if 0 == csize { break }
if 0 == csize {
break
}
cscanner.skip_crlf()
sb.write( cscanner.read_chunk(csize) )
sb.write(cscanner.read_chunk(csize))
cscanner.skip_crlf()
}
cscanner.skip_crlf()
return sb.str()
}

View File

@ -1,14 +1,16 @@
// 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
import os
pub fn download_file(url, out string) bool {
s := http.get(url) or { return false }
s := http.get(url) or {
return false
}
os.write_file(out, s.text)
return true
//download_file_with_progress(url, out, empty, empty)
// download_file_with_progress(url, out, empty, empty)
}

View File

@ -1,12 +1,9 @@
// 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
type downloadfn fn (written int)
type download_finished_fn fn ()
type downloadfn fn(written int)type download_finished_fn fn()
/*
struct DownloadStruct {
mut:
@ -15,9 +12,8 @@ mut:
cb downloadfn
}
*/
fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
/*
fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
/*
mut data := &DownloadStruct(userp)
written := C.fwrite(ptr, size, nmemb, data.stream)
data.written += written
@ -28,7 +24,7 @@ fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
}
pub fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) {
/*
/*
curl := C.curl_easy_init()
if isnil(curl) {
return
@ -52,6 +48,5 @@ pub fn download_file_with_progress(url, out string, cb downloadfn, cb_finished f
}
fn empty() {
}

View File

@ -1,7 +1,6 @@
// 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
import net.urllib
@ -13,19 +12,19 @@ const (
pub struct Request {
pub:
headers map[string]string
method string
headers map[string]string
method string
// cookies map[string]string
h string
cmd string
typ string // GET POST
data string
url string
verbose bool
h string
cmd string
typ string // GET POST
data string
url string
verbose bool
user_agent string
mut:
user_ptr voidptr
ws_func voidptr
user_ptr voidptr
ws_func voidptr
}
pub struct Response {
@ -67,7 +66,7 @@ pub fn new_request(typ, _url, _data string) ?Request {
url = '$url?$data'
data = ''
}
return Request {
return Request{
typ: typ
url: url
data: data
@ -79,7 +78,9 @@ pub fn new_request(typ, _url, _data string) ?Request {
}
pub fn get_text(url string) string {
resp := get(url) or { return '' }
resp := get(url) or {
return ''
}
return resp.text
}
@ -116,18 +117,29 @@ pub fn (req &Request) do() ?Response {
if req.typ == 'POST' {
// req.headers << 'Content-Type: application/x-www-form-urlencoded'
}
url := urllib.parse(req.url) or { return error('http.request.do: invalid URL "$req.url"') }
url := urllib.parse(req.url) or {
return error('http.request.do: invalid URL "$req.url"')
}
mut rurl := url
mut resp := Response{}
mut resp := Response{
}
mut no_redirects := 0
for {
if no_redirects == max_redirects { return error('http.request.do: maximum number of redirects reached ($max_redirects)') }
qresp := req.method_and_url_to_response( req.typ, rurl ) or { return error(err) }
if no_redirects == max_redirects {
return error('http.request.do: maximum number of redirects reached ($max_redirects)')
}
qresp := req.method_and_url_to_response(req.typ, rurl) or {
return error(err)
}
resp = qresp
if ! (resp.status_code in [301, 302, 303, 307, 308]) { break }
if !(resp.status_code in [301, 302, 303, 307, 308]) {
break
}
// follow any redirects
redirect_url := resp.headers['Location']
qrurl := urllib.parse( redirect_url ) or { return error('http.request.do: invalid URL in redirect "$redirect_url"') }
qrurl := urllib.parse(redirect_url) or {
return error('http.request.do: invalid URL in redirect "$redirect_url"')
}
rurl = qrurl
no_redirects++
}
@ -141,19 +153,24 @@ fn (req &Request) method_and_url_to_response(method string, url net_dot_urllib.U
path := if url.query().size > 0 { '/$p?${url.query().encode()}' } else { '/$p' }
mut nport := url.port().int()
if nport == 0 {
if scheme == 'http' { nport = 80 }
if scheme == 'https' { nport = 443 }
if scheme == 'http' {
nport = 80
}
if scheme == 'https' {
nport = 443
}
}
//println('fetch $method, $scheme, $host_name, $nport, $path ')
// println('fetch $method, $scheme, $host_name, $nport, $path ')
if scheme == 'https' {
//println('ssl_do( $nport, $method, $host_name, $path )')
res := req.ssl_do( nport, method, host_name, path ) or {
// println('ssl_do( $nport, $method, $host_name, $path )')
res := req.ssl_do(nport, method, host_name, path) or {
return error(err)
}
return res
} else if scheme == 'http' {
//println('http_do( $nport, $method, $host_name, $path )')
res := req.http_do(nport, method, host_name, path ) or {
}
else if scheme == 'http' {
// println('http_do( $nport, $method, $host_name, $path )')
res := req.http_do(nport, method, host_name, path) or {
return error(err)
}
return res
@ -175,7 +192,7 @@ fn parse_response(resp string) Response {
mut i := 1
for {
old_pos := nl_pos
nl_pos = resp.index_after('\n', nl_pos+1)
nl_pos = resp.index_after('\n', nl_pos + 1)
if nl_pos == -1 {
break
}
@ -189,19 +206,17 @@ fn parse_response(resp string) Response {
pos := h.index(':') or {
continue
}
//if h.contains('Content-Type') {
//continue
//}
// if h.contains('Content-Type') {
// continue
// }
key := h[..pos]
val := h[pos+2..]
val := h[pos + 2..]
headers[key] = val.trim_space()
}
if headers['Transfer-Encoding'] == 'chunked' {
text = chunked.decode( text )
text = chunked.decode(text)
}
return Response {
return Response{
status_code: status_code
headers: headers
text: text
@ -217,12 +232,7 @@ fn (req &Request) build_request_headers(method, host_name, path string) string {
if req.data.len > 0 {
uheaders << 'Content-Length: ${req.data.len}\r\n'
}
return '$method $path HTTP/1.1\r\n' +
'Host: $host_name\r\n' +
'User-Agent: $ua\r\n' +
uheaders.join('') +
'Connection: close\r\n\r\n' +
req.data
return '$method $path HTTP/1.1\r\n' + 'Host: $host_name\r\n' + 'User-Agent: $ua\r\n' + uheaders.join('') + 'Connection: close\r\n\r\n' + req.data
}
pub fn unescape_url(s string) string {
@ -241,4 +251,5 @@ pub fn escape(s string) string {
panic('http.escape() was replaced with http.escape_url()')
}
type wsfn fn (s string, ptr voidptr)
type wsfn fn(s string, ptr voidptr)

View File

@ -8,15 +8,23 @@ fn (req &Request) http_do(port int, method, host_name, path string) ?Response {
rbuffer := [512]byte
mut sb := strings.new_builder(100)
s := req.build_request_headers(method, host_name, path)
client := net.dial( host_name, port) or { return error(err) }
client.send( s.str, s.len ) or {}
for {
readbytes := client.crecv( rbuffer, bufsize )
if readbytes < 0 { return error('http.request.http_do: error reading response. readbytes=$readbytes') }
if readbytes == 0 { break }
sb.write( tos(rbuffer, readbytes) )
client := net.dial(host_name, port) or {
return error(err)
}
client.send(s.str, s.len) or {
}
for {
readbytes := client.crecv(rbuffer, bufsize)
if readbytes < 0 {
return error('http.request.http_do: error reading response. readbytes=$readbytes')
}
if readbytes == 0 {
break
}
sb.write(tos(rbuffer, readbytes))
}
client.close() or {
}
client.close() or {}
return parse_response(sb.str())
}