51354e | 2016-05-13 | Pontus Östlund | |
|
2612f7 | 2017-03-01 | Anders Johansson | |
|
51354e | 2016-05-13 | Pontus Östlund | |
#ifdef HTTP_CLIENT_DEBUG
# define TRACE(X...)werror("%s:%d: %s",basename(__FILE__),__LINE__,sprintf(X))
#else
# define TRACE(X...)0
#endif
protected constant DEFAULT_MAXTIME = 60;
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public Result sync_get(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | return do_safe_method("GET", uri, args, false, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public Result sync_post(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | return do_safe_method("POST", uri, args, false, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public Result sync_put(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | return do_safe_method("PUT", uri, args, false, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public Result sync_delete(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | return do_safe_method("DELETE", uri, args, false, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public void async_get(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | do_safe_method("GET", uri, args, true, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public void async_post(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | do_safe_method("POST", uri, args, true, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public void async_put(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | do_safe_method("PUT", uri, args, true, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | public void async_delete(Protocols.HTTP.Session.URL uri,
void|Arguments args,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | do_safe_method("DELETE", uri, args, true, session);
|
51354e | 2016-05-13 | Pontus Östlund | | }
public Result do_safe_method(string http_method,
Protocols.HTTP.Session.URL uri,
void|Arguments args,
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | void|bool async,
void|Session session)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
ea3bea | 2016-05-13 | Pontus Östlund | | if (!args) {
args = Arguments();
}
|
51354e | 2016-05-13 | Pontus Östlund | | Result res;
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | Session s = session || Session();
|
298aef | 2017-04-25 | Karl Gustav Sterneberg | | if (args && args->follow_redirects > -1) {
s->follow_redirects = args->follow_redirects;
}
|
51354e | 2016-05-13 | Pontus Östlund | | object qr;
Thread.Queue q;
mixed co_maxtime;
if (args->maxtime) s->maxtime = args->maxtime;
if (args->timeout) s->timeout = args->timeout;
if (!async) {
q = Thread.Queue();
}
|
1615cc | 2016-05-20 | Pontus Östlund | | function(Result:void) cb = lambda (Result r) {
TRACE("Got callback: %O\n", r);
res = r;
q && q->write("@");
if (async) {
if (r->ok && args->on_success) {
args->on_success(res);
}
else if (!r->ok && args->on_failure) {
args->on_failure(r);
}
qr = 0;
s = 0;
}
};
|
51354e | 2016-05-13 | Pontus Östlund | | qr = s->async_do_method_url(http_method, uri,
args->variables,
args->data,
args->headers,
|
1615cc | 2016-05-20 | Pontus Östlund | | 0,
cb,
cb,
|
aeb389 | 2017-03-01 | Pontus Östlund | | args->extra_args || ({}));
|
51354e | 2016-05-13 | Pontus Östlund | |
if (!query_has_maxtime()) {
|
aeb389 | 2017-03-01 | Pontus Östlund | | TRACE("No maxtime in Protocols.HTTP.Query. Set external max timeout: %O\n",
s->maxtime || DEFAULT_MAXTIME);
|
51354e | 2016-05-13 | Pontus Östlund | | co_maxtime = call_out(lambda () {
TRACE("Timeout callback: %O\n", qr);
res = Failure(([
"status" : 504,
"status_desc" : "Gateway timeout",
"host" : qr->con->host,
"headers" : qr->con->headers,
"url" : qr->url_requested
]));
qr->set_callbacks(0, 0, 0, 0);
qr->con->set_callbacks(0, 0, 0);
destruct(qr);
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | | s = 0;
|
51354e | 2016-05-13 | Pontus Östlund | |
q && q->write("@");
if (async) {
if (args->on_failure) {
args->on_failure(res);
}
qr = 0;
s = 0;
}
}, s->maxtime || DEFAULT_MAXTIME);
}
if (!async) {
q->read();
}
if (co_maxtime && co_maxtime[0]) {
TRACE("Remove timeout callout\n");
remove_call_out(co_maxtime);
}
if (!async) {
q = 0;
qr = 0;
s = 0;
}
return res;
}
protected int(-1..1) _query_has_maxtime = -1;
protected bool query_has_maxtime()
{
if (_query_has_maxtime != -1) {
return _query_has_maxtime == 1;
}
Protocols.HTTP.Query q = Protocols.HTTP.Query();
_query_has_maxtime = (int) has_index(q, "maxtime");
destruct(q);
|
1615cc | 2016-05-20 | Pontus Östlund | | return _query_has_maxtime == 1;
|
51354e | 2016-05-13 | Pontus Östlund | | }
class Arguments
{
int timeout;
int maxtime;
|
298aef | 2017-04-25 | Karl Gustav Sterneberg | |
int follow_redirects = -1;
|
51354e | 2016-05-13 | Pontus Östlund | |
mapping(string:string) headers;
mapping(string:mixed) variables;
|
0b9ed4 | 2018-10-15 | Karl Gustav Sterneberg | | void|string|mapping|Stdio.Stream data;
|
51354e | 2016-05-13 | Pontus Östlund | |
function(Result:void) on_success;
function(Result:void) on_failure;
|
aeb389 | 2017-03-01 | Pontus Östlund | |
array(mixed) extra_args;
|
51354e | 2016-05-13 | Pontus Östlund | |
|
1615cc | 2016-05-20 | Pontus Östlund | |
|
51354e | 2016-05-13 | Pontus Östlund | | protected void create(void|mapping(string:mixed) args)
{
if (args) {
|
aeb389 | 2017-03-01 | Pontus Östlund | | foreach (args; string key; mixed value) {
|
51354e | 2016-05-13 | Pontus Östlund | | if (has_index(this, key)) {
|
aeb389 | 2017-03-01 | Pontus Östlund | | if ((< "variables", "headers" >)[key]) {
value = mkmapping(indices(value), map(values(value),
lambda (mixed s) {
return (string) s;
}));
}
this[key] = value;
}
else {
error("Unknown argument %O!\n", key);
|
51354e | 2016-05-13 | Pontus Östlund | | }
}
}
}
}
class Result
{
protected mapping result;
public bool `ok();
public mapping `headers()
{
return result->headers;
}
public string `host()
{
return result->host;
}
public int `status()
{
return result->status;
}
public string `status_description()
{
return result->status_desc;
}
public string `url()
{
return result->url;
}
|
aeb389 | 2017-03-01 | Pontus Östlund | |
public array(mixed) `extra_args()
{
return result->extra_args;
}
|
51354e | 2016-05-13 | Pontus Östlund | |
protected void create(mapping _result)
{
result = _result;
}
}
class Success
{
inherit Result;
public bool `ok() { return true; }
|
4b426d | 2017-04-12 | Pontus Östlund | | public string `data()
{
string data = result->data;
if (content_encoding && content_encoding == "gzip") {
data = Gz.uncompress(data[10..<8], true);
}
return data;
}
|
51354e | 2016-05-13 | Pontus Östlund | |
public int `length()
{
return headers && (int)headers["content-length"];
}
public string `content_type()
{
if (string ct = (headers && headers["content-type"])) {
sscanf (ct, "%s;", ct);
return ct;
}
}
|
4b426d | 2017-04-12 | Pontus Östlund | |
|
51354e | 2016-05-13 | Pontus Östlund | |
|
4b426d | 2017-04-12 | Pontus Östlund | | public string `charset()
|
51354e | 2016-05-13 | Pontus Östlund | | {
if (string ce = (headers && headers["content-type"])) {
if (sscanf (ce, "%*s;%*scharset=%s", ce) == 3) {
if (ce[0] == '"' || ce[0] == '\'') {
ce = ce[1..<1];
}
return ce;
}
}
}
|
4b426d | 2017-04-12 | Pontus Östlund | |
public string `content_encoding()
{
if (string ce = (headers && headers["content-encoding"])) {
return ce;
}
}
|
51354e | 2016-05-13 | Pontus Östlund | | }
class Failure
{
inherit Result;
public bool `ok() { return false; }
}
|
8dfff6 | 2018-10-15 | Karl Gustav Sterneberg | |
public class Session
|
51354e | 2016-05-13 | Pontus Östlund | | {
inherit Protocols.HTTP.Session : parent;
public int(0..) maxtime, timeout;
public int maximum_connections_per_server = 20;
Request async_do_method_url(string method,
URL url,
void|mapping query_variables,
|
0b9ed4 | 2018-10-15 | Karl Gustav Sterneberg | | void|string|mapping|Stdio.Stream data,
|
51354e | 2016-05-13 | Pontus Östlund | | void|mapping extra_headers,
function callback_headers_ok,
function callback_data_ok,
function callback_fail,
array callback_arguments)
{
|
1615cc | 2016-05-20 | Pontus Östlund | | if (stringp(url)) {
url = Standards.URI(url);
}
if (!extra_headers || !extra_headers->host || !extra_headers->Host) {
extra_headers = extra_headers || ([]);
|
aeb389 | 2017-03-01 | Pontus Östlund | | TRACE("Set host in headers: %O\n", url);
if (url->scheme == "http") {
extra_headers->host = url->host;
if (url->port != 80) {
extra_headers->host += ":" + url->port;
}
|
1615cc | 2016-05-20 | Pontus Östlund | | }
|
aeb389 | 2017-03-01 | Pontus Östlund | | else if (url->scheme == "https") {
extra_headers->host = url->host;
if (url->port != 443) {
extra_headers->host += ":" + url->port;
}
|
1615cc | 2016-05-20 | Pontus Östlund | | }
if (!sizeof(extra_headers)) {
extra_headers = 0;
}
TRACE("Host header set?: %O\n", extra_headers);
}
|
4b426d | 2017-04-12 | Pontus Östlund | | if (upper_case(method) == "POST") {
TRACE("Got post request: %O, %O, %O, %O\n",
url, query_variables, data, extra_headers);
bool has_content_len = false;
bool has_content_type = false;
if (extra_headers) {
array(string) lc_headers = map(indices(extra_headers), lower_case);
if (has_value(lc_headers, "content-length")) {
has_content_len = true;
}
if (has_value(lc_headers, "content-type")) {
has_content_type = true;
}
}
if (!has_content_len) {
mapping(string:string) qvars = url->get_query_variables();
data = data||"";
if (qvars && sizeof(qvars)) {
if (!query_variables) {
query_variables = qvars;
}
else {
query_variables |= qvars;
}
}
if (sizeof(data) && query_variables) {
data += "&" + Protocols.HTTP.http_encode_query(query_variables);
}
else if (query_variables) {
data = Protocols.HTTP.http_encode_query(query_variables);
}
if (!extra_headers) {
extra_headers = ([]);
}
extra_headers["Content-Length"] = (string) sizeof(data);
if (!has_content_type) {
extra_headers["Content-Type"] = "application/x-www-form-urlencoded";
}
query_variables = 0;
}
}
|
aeb389 | 2017-03-01 | Pontus Östlund | | TRACE("Request: %O\n", url);
|
0b9ed4 | 2018-10-15 | Karl Gustav Sterneberg | |
|
51354e | 2016-05-13 | Pontus Östlund | | return ::async_do_method_url(method, url, query_variables, data,
extra_headers, callback_headers_ok,
callback_data_ok, callback_fail,
callback_arguments);
}
class Request
{
inherit parent::Request;
|
aeb389 | 2017-03-01 | Pontus Östlund | | protected void set_extra_args_in_result(mapping(string:mixed) r)
{
if (extra_callback_arguments && sizeof(extra_callback_arguments) > 1) {
r->extra_args = extra_callback_arguments[1..];
}
}
|
1615cc | 2016-05-20 | Pontus Östlund | | protected void async_fail(SessionQuery q)
|
51354e | 2016-05-13 | Pontus Östlund | | {
|
1615cc | 2016-05-20 | Pontus Östlund | | TRACE("fail q: %O -> %O\n", q, ::url_requested);
|
51354e | 2016-05-13 | Pontus Östlund | |
mapping ret = ([
"status" : q->status,
"status_desc" : q->status_desc,
"host" : q->host,
"headers" : copy_value(q->headers),
"url" : ::url_requested
]);
|
1615cc | 2016-05-20 | Pontus Östlund | | TRACE("Ret: %O\n", ret);
|
aeb389 | 2017-03-01 | Pontus Östlund | | set_extra_args_in_result(ret);
|
51354e | 2016-05-13 | Pontus Östlund | |
con->set_callbacks(0, 0);
function fc = fail_callback;
set_callbacks(0, 0, 0);
extra_callback_arguments = 0;
if (fc) {
fc(Failure(ret));
}
}
|
1615cc | 2016-05-20 | Pontus Östlund | | protected void async_ok(SessionQuery q)
|
51354e | 2016-05-13 | Pontus Östlund | | {
TRACE("async_ok: %O -> %s!\n", q->host, ::url_requested);
::check_for_cookies();
if (con->status >= 300 && con->status < 400 &&
con->headers->location && follow_redirects)
{
Standards.URI loc = Standards.URI(con->headers->location,url_requested);
|
1615cc | 2016-05-20 | Pontus Östlund | | TRACE("New location: %O -> %O (%O)\n", url_requested, loc, con->headers);
|
51354e | 2016-05-13 | Pontus Östlund | |
if (loc->scheme == "http" || loc->scheme == "https") {
|
1615cc | 2016-05-20 | Pontus Östlund | | con->set_callbacks(0, 0);
::destroy();
|
51354e | 2016-05-13 | Pontus Östlund | | follow_redirects--;
do_async(prepare_method("GET", loc));
return;
}
}
con->set_callbacks(0, 0);
if (data_callback) {
|
aeb389 | 2017-03-01 | Pontus Östlund | | con->async_fetch(async_data);
|
51354e | 2016-05-13 | Pontus Östlund | | }
else {
extra_callback_arguments = 0;
}
}
protected void async_data()
{
mapping ret = ([
"host" : con->host,
"status" : con->status,
"status_desc" : con->status_desc,
"headers" : copy_value(con->headers),
"data" : con->data(),
"url" : ::url_requested
]);
|
aeb389 | 2017-03-01 | Pontus Östlund | | set_extra_args_in_result(ret);
|
51354e | 2016-05-13 | Pontus Östlund | |
con->set_callbacks(0, 0);
if (data_callback) {
data_callback(Success(ret));
}
extra_callback_arguments = 0;
}
void destroy()
{
TRACE("Destructor called in Request: %O\n", ::url_requested);
|
1615cc | 2016-05-20 | Pontus Östlund | | ::set_callbacks(0, 0, 0);
|
51354e | 2016-05-13 | Pontus Östlund | | ::destroy();
}
}
class SessionQuery
{
inherit parent::SessionQuery;
protected void create()
{
#if constant (this::maxtime)
TRACE("# Query has maxtime\n");
if (Session::maxtime) {
this::maxtime = Session::maxtime;
}
#endif
if (Session::timeout) {
this::timeout = Session::timeout;
}
}
|
0b9ed4 | 2018-10-15 | Karl Gustav Sterneberg | |
protected Stdio.Stream source_stream;
protected int source_stream_length;
this_program async_request (string server,
int port,
string query,
void|mapping|string headers,
void|string|Stdio.Stream data)
{
if (objectp(data)) {
set_source_stream(data);
data = UNDEFINED;
}
if (source_stream) {
if (data)
error ("String data not allowed in streaming mode.\n");
if (stringp (headers))
error ("String headers not allowed in streaming mode.\n");
if (!headers)
headers = ([]);
headers["Content-Length"] = source_stream_length;
}
::async_request (server, port, query, headers, data);
}
protected void async_write()
{
::async_write();
if (!con->query_write_callback() && source_stream) {
Stdio.sendfile (0, source_stream, 0, source_stream_length, 0, con,
lambda(int bytes_sent) {
source_stream->close(); source_stream = 0;
});
}
}
void set_source_stream (Stdio.Stream s)
{
source_stream = s;
source_stream_length = s->stat()->size;
}
this_program sync_request(string server,
int port,
string query,
void|mapping|string http_headers,
void|string|Stdio.Stream data)
{
if (objectp(data)) {
string tmp = data->read(0x7fffffff);
data->close();
data = tmp;
}
return ::sync_request(server, port, query, http_headers, data);
}
|
51354e | 2016-05-13 | Pontus Östlund | | }
}
|