class Client
class Client
lib/net/http/client.tya:2
Client provides the net/http/Client standard library API.
Source
# Client provides the net/http/Client standard library API.
class Client
# Client.target stores instance state.
# @type Nil
target: nil
# Client.initialize stores a target URL.
# @param target Any target value.
# @return Self the initialized object.
initialize: target ->
self.target = target
# Client.chomp provides the net/http/Client standard library operation.
# @param text String text value.
# @return Any the resulting value.
chomp: text ->
n = text.byte_len()
if n > 0 and text[n - 1] == "\n"
n = n - 1
if n > 0 and text[n - 1] == chr(13)
n = n - 1
text.slice(0, n)
# Client.get provides the net/http/Client standard library operation.
# @param target Any target value.
# @return Any the resulting value.
get: target = nil ->
if target == nil
target = self.target
Client(target).request("GET", {})
# Client.hex_to_i provides the net/http/Client standard library operation.
# @param text String text value.
# @return Any the resulting value.
hex_to_i: text ->
value = 0
i = 0
while i < text.byte_len()
c = ord(text[i])
digit = -1
if c >= 48 and c <= 57
digit = c - 48
elseif c >= 65 and c <= 70
digit = c - 55
else
if c >= 97 and c <= 102
digit = c - 87
else
raise error("http.response: invalid chunk size")
value = value * 16 + digit
i = i + 1
value
# Client.host_header provides the net/http/Client standard library operation.
# @param host String host value.
# @param port Any port value.
# @return Any the resulting value.
host_header: host, port ->
if port == "" or port == "80" or port == "443"
return host
host + ":" + port
# Client.index_of provides the net/http/Client standard library operation.
# @param text String text value.
# @param needle Any needle value.
# @param start Int start value.
# @return Any the resulting value.
index_of: text, needle, start ->
i = start
n = text.byte_len()
m = needle.byte_len()
while i + m <= n
if text.slice(i, i + m) == needle
return i
i = i + 1
-1
# Client.parse_url provides the net/http/Client standard library operation.
# @param target Any target value.
# @return String the resulting value.
parse_url: target ->
prefix = "http://"
scheme = "http"
if target.starts_with("https://")
prefix = "https://"
scheme = "https"
elseif not target.starts_with(prefix)
raise error("http.request: only http:// and https:// URLs are supported")
rest = target.slice(prefix.len(), target.len())
slash = Client(nil).index_of(rest, "/", 0)
query = Client(nil).index_of(rest, "?", 0)
end_auth = rest.byte_len()
if slash >= 0 and slash < end_auth
end_auth = slash
if query >= 0 and query < end_auth
end_auth = query
authority = rest.slice(0, end_auth)
remainder = rest.slice(end_auth, rest.len())
host = authority
port = ""
colon = Client(nil).index_of(authority, ":", 0)
if colon >= 0
host = authority.slice(0, colon)
port = authority.slice(colon + 1, authority.len())
path = remainder
query_text = ""
has_query = false
q = Client(nil).index_of(remainder, "?", 0)
if q >= 0
has_query = true
path = remainder.slice(0, q)
query_text = remainder.slice(q + 1, remainder.len())
if path == ""
path = "/"
{ scheme: scheme, host: host, port: port, path: path, query: query_text, has_query: has_query }
# Client.post provides the net/http/Client standard library operation.
# @param target Any target value.
# @param body String body value.
# @return Any the resulting value.
post: target, body = nil ->
if self.target != nil
body = target
target = self.target
Client(target).request("POST", { body: body })
# Client.read_chunked provides the net/http/Client standard library operation.
# @param s Any s value.
# @return Any the resulting value.
read_chunked: s ->
out = ""
size_line = socket_read_line(s)
while size_line != nil
size_text = Client(nil).chomp(size_line).split(";")[0].trim()
size = Client(nil).hex_to_i(size_text)
if size == 0
Client(nil).read_trailers(s)
return out
out = out + socket_read(s, size)
socket_read_line(s)
size_line = socket_read_line(s)
out
# Client.read_response provides the net/http/Client standard library operation.
# @param s Any s value.
# @return Any the resulting value.
read_response: s ->
status_line = socket_read_line(s)
if status_line == nil
raise error("http.response: empty response")
status_line = Client(nil).chomp(status_line)
parts = status_line.split(" ")
if parts.len() < 2
raise error("http.response: invalid status line")
status = parts[1].to_i()
headers = {}
line = socket_read_line(s)
while line != nil and Client(nil).chomp(line) != ""
clean = Client(nil).chomp(line)
idx = Client(nil).index_of(clean, ":", 0)
if idx > 0
name = clean.slice(0, idx).lower()
value = clean.slice(idx + 1, clean.len()).trim()
headers[name] = value
line = socket_read_line(s)
body = ""
transfer = headers.get("transfer-encoding", "")
if transfer.lower().contains("chunked")
body = Client(nil).read_chunked(s)
elseif headers.has("content-length")
body = socket_read(s, headers["content-length"].to_i())
else
chunk = socket_read(s, 4096)
while chunk != nil and chunk != ""
body = body + chunk
chunk = socket_read(s, 4096)
{ status: status, headers: headers, body: body }
# Client.read_trailers provides the net/http/Client standard library operation.
# @param s Any s value.
# @return Any the resulting value.
read_trailers: s ->
line = socket_read_line(s)
while line != nil and Client(nil).chomp(line) != ""
line = socket_read_line(s)
nil
# Client.request provides the net/http/Client standard library operation.
# @param method String method value.
# @param target Any target value.
# @param opts Any opts value.
# @return Any the resulting value.
request: method, target = nil, opts = nil ->
if self.target != nil
opts = target
target = self.target
if opts == nil
opts = {}
u = Client(nil).parse_url(target)
if u["scheme"] != "http" and u["scheme"] != "https"
raise error("http.request: only http:// and https:// URLs are supported")
host = u["host"]
if host == ""
raise error("http.request: URL host is required")
port = 80
if u["scheme"] == "https"
port = 443
if u["port"] != ""
port = u["port"].to_i()
path = u["path"]
if path == ""
path = "/"
if u["has_query"]
path = path + "?" + u["query"]
headers = {}
if opts.has("headers") and opts["headers"] != nil
headers = opts["headers"]
body = ""
if opts.has("body") and opts["body"] != nil
body = opts["body"].to_s()
crlf = chr(13) + "\n"
req = method.upper() + " " + path + " HTTP/1.1" + crlf
req = req + "Host: " + Client(nil).host_header(host, u["port"]) + crlf
req = req + "Connection: close" + crlf
if body != ""
req = req + "Content-Length: " + body.byte_len().to_s() + crlf
for entry in headers.entries()
req = req + entry[0] + ": " + entry[1].to_s() + crlf
req = req + crlf + body
connect_options = { timeout: opts.get("timeout", 10) }
if opts.has("insecure_skip_verify")
connect_options["insecure_skip_verify"] = opts["insecure_skip_verify"]
if opts.has("ca_file")
connect_options["ca_file"] = opts["ca_file"]
s = nil
if u["scheme"] == "https"
s = tls_connect(host, port, connect_options)
else
s = socket_connect(host, port, connect_options)
socket_write(s, req)
response = Client(nil).read_response(s)
socket_close(s)
response
Instance Variables
target
Client.target
lib/net/http/client.tya:5
Client.target stores instance state.
Source
# Client.target stores instance state.
# @type Nil
target: nil
Methods
chomp
Client.chomp(text)
lib/net/http/client.tya:16
Client.chomp provides the net/http/Client standard library operation.
Source
# Client.chomp provides the net/http/Client standard library operation.
# @param text String text value.
# @return Any the resulting value.
chomp: text ->
n = text.byte_len()
if n > 0 and text[n - 1] == "\n"
n = n - 1
if n > 0 and text[n - 1] == chr(13)
n = n - 1
text.slice(0, n)
get
Client.get(target = nil)
lib/net/http/client.tya:27
Client.get provides the net/http/Client standard library operation.
Source
# Client.get provides the net/http/Client standard library operation.
# @param target Any target value.
# @return Any the resulting value.
get: target = nil ->
if target == nil
target = self.target
Client(target).request("GET", {})
hex_to_i
Client.hex_to_i(text)
lib/net/http/client.tya:35
Client.hex_to_i provides the net/http/Client standard library operation.
Source
# Client.hex_to_i provides the net/http/Client standard library operation.
# @param text String text value.
# @return Any the resulting value.
hex_to_i: text ->
value = 0
i = 0
while i < text.byte_len()
c = ord(text[i])
digit = -1
if c >= 48 and c <= 57
digit = c - 48
elseif c >= 65 and c <= 70
digit = c - 55
else
if c >= 97 and c <= 102
digit = c - 87
else
raise error("http.response: invalid chunk size")
value = value * 16 + digit
i = i + 1
value
host_header
Client.host_header(host, port)
lib/net/http/client.tya:58
Client.host_header provides the net/http/Client standard library operation.
Source
# Client.host_header provides the net/http/Client standard library operation.
# @param host String host value.
# @param port Any port value.
# @return Any the resulting value.
host_header: host, port ->
if port == "" or port == "80" or port == "443"
return host
host + ":" + port
index_of
Client.index_of(text, needle, start)
lib/net/http/client.tya:68
Client.index_of provides the net/http/Client standard library operation.
Source
# Client.index_of provides the net/http/Client standard library operation.
# @param text String text value.
# @param needle Any needle value.
# @param start Int start value.
# @return Any the resulting value.
index_of: text, needle, start ->
i = start
n = text.byte_len()
m = needle.byte_len()
while i + m <= n
if text.slice(i, i + m) == needle
return i
i = i + 1
-1
initialize
Client.initialize(target)
lib/net/http/client.tya:10
Client.initialize stores a target URL.
Source
# Client.initialize stores a target URL.
# @param target Any target value.
# @return Self the initialized object.
initialize: target ->
self.target = target
parse_url
Client.parse_url(target)
lib/net/http/client.tya:81
Client.parse_url provides the net/http/Client standard library operation.
Source
# Client.parse_url provides the net/http/Client standard library operation.
# @param target Any target value.
# @return String the resulting value.
parse_url: target ->
prefix = "http://"
scheme = "http"
if target.starts_with("https://")
prefix = "https://"
scheme = "https"
elseif not target.starts_with(prefix)
raise error("http.request: only http:// and https:// URLs are supported")
rest = target.slice(prefix.len(), target.len())
slash = Client(nil).index_of(rest, "/", 0)
query = Client(nil).index_of(rest, "?", 0)
end_auth = rest.byte_len()
if slash >= 0 and slash < end_auth
end_auth = slash
if query >= 0 and query < end_auth
end_auth = query
authority = rest.slice(0, end_auth)
remainder = rest.slice(end_auth, rest.len())
host = authority
port = ""
colon = Client(nil).index_of(authority, ":", 0)
if colon >= 0
host = authority.slice(0, colon)
port = authority.slice(colon + 1, authority.len())
path = remainder
query_text = ""
has_query = false
q = Client(nil).index_of(remainder, "?", 0)
if q >= 0
has_query = true
path = remainder.slice(0, q)
query_text = remainder.slice(q + 1, remainder.len())
if path == ""
path = "/"
{ scheme: scheme, host: host, port: port, path: path, query: query_text, has_query: has_query }
post
Client.post(target, body = nil)
lib/net/http/client.tya:121
Client.post provides the net/http/Client standard library operation.
Source
# Client.post provides the net/http/Client standard library operation.
# @param target Any target value.
# @param body String body value.
# @return Any the resulting value.
post: target, body = nil ->
if self.target != nil
body = target
target = self.target
Client(target).request("POST", { body: body })
read_chunked
Client.read_chunked(s)
lib/net/http/client.tya:130
Client.read_chunked provides the net/http/Client standard library operation.
Source
# Client.read_chunked provides the net/http/Client standard library operation.
# @param s Any s value.
# @return Any the resulting value.
read_chunked: s ->
out = ""
size_line = socket_read_line(s)
while size_line != nil
size_text = Client(nil).chomp(size_line).split(";")[0].trim()
size = Client(nil).hex_to_i(size_text)
if size == 0
Client(nil).read_trailers(s)
return out
out = out + socket_read(s, size)
socket_read_line(s)
size_line = socket_read_line(s)
out
read_response
Client.read_response(s)
lib/net/http/client.tya:147
Client.read_response provides the net/http/Client standard library operation.
Source
# Client.read_response provides the net/http/Client standard library operation.
# @param s Any s value.
# @return Any the resulting value.
read_response: s ->
status_line = socket_read_line(s)
if status_line == nil
raise error("http.response: empty response")
status_line = Client(nil).chomp(status_line)
parts = status_line.split(" ")
if parts.len() < 2
raise error("http.response: invalid status line")
status = parts[1].to_i()
headers = {}
line = socket_read_line(s)
while line != nil and Client(nil).chomp(line) != ""
clean = Client(nil).chomp(line)
idx = Client(nil).index_of(clean, ":", 0)
if idx > 0
name = clean.slice(0, idx).lower()
value = clean.slice(idx + 1, clean.len()).trim()
headers[name] = value
line = socket_read_line(s)
body = ""
transfer = headers.get("transfer-encoding", "")
if transfer.lower().contains("chunked")
body = Client(nil).read_chunked(s)
elseif headers.has("content-length")
body = socket_read(s, headers["content-length"].to_i())
else
chunk = socket_read(s, 4096)
while chunk != nil and chunk != ""
body = body + chunk
chunk = socket_read(s, 4096)
{ status: status, headers: headers, body: body }
read_trailers
Client.read_trailers(s)
lib/net/http/client.tya:182
Client.read_trailers provides the net/http/Client standard library operation.
Source
# Client.read_trailers provides the net/http/Client standard library operation.
# @param s Any s value.
# @return Any the resulting value.
read_trailers: s ->
line = socket_read_line(s)
while line != nil and Client(nil).chomp(line) != ""
line = socket_read_line(s)
nil
request
Client.request(method, target = nil, opts = nil)
lib/net/http/client.tya:193
Client.request provides the net/http/Client standard library operation.
Source
# Client.request provides the net/http/Client standard library operation.
# @param method String method value.
# @param target Any target value.
# @param opts Any opts value.
# @return Any the resulting value.
request: method, target = nil, opts = nil ->
if self.target != nil
opts = target
target = self.target
if opts == nil
opts = {}
u = Client(nil).parse_url(target)
if u["scheme"] != "http" and u["scheme"] != "https"
raise error("http.request: only http:// and https:// URLs are supported")
host = u["host"]
if host == ""
raise error("http.request: URL host is required")
port = 80
if u["scheme"] == "https"
port = 443
if u["port"] != ""
port = u["port"].to_i()
path = u["path"]
if path == ""
path = "/"
if u["has_query"]
path = path + "?" + u["query"]
headers = {}
if opts.has("headers") and opts["headers"] != nil
headers = opts["headers"]
body = ""
if opts.has("body") and opts["body"] != nil
body = opts["body"].to_s()
crlf = chr(13) + "\n"
req = method.upper() + " " + path + " HTTP/1.1" + crlf
req = req + "Host: " + Client(nil).host_header(host, u["port"]) + crlf
req = req + "Connection: close" + crlf
if body != ""
req = req + "Content-Length: " + body.byte_len().to_s() + crlf
for entry in headers.entries()
req = req + entry[0] + ": " + entry[1].to_s() + crlf
req = req + crlf + body
connect_options = { timeout: opts.get("timeout", 10) }
if opts.has("insecure_skip_verify")
connect_options["insecure_skip_verify"] = opts["insecure_skip_verify"]
if opts.has("ca_file")
connect_options["ca_file"] = opts["ca_file"]
s = nil
if u["scheme"] == "https"
s = tls_connect(host, port, connect_options)
else
s = socket_connect(host, port, connect_options)
socket_write(s, req)
response = Client(nil).read_response(s)
socket_close(s)
response