mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 09:40:21 +00:00
1470 lines
55 KiB
Plaintext
1470 lines
55 KiB
Plaintext
#define __http_init
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Creates global.__HttpClient
|
|
// real __http_init()
|
|
|
|
global.__HttpClient = object_add();
|
|
object_set_persistent(global.__HttpClient, true);
|
|
|
|
#define __http_split
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// real __http_split(string text, delimeter delimeter, real limit)
|
|
// Splits string into items
|
|
|
|
// text - string comma-separated values
|
|
// delimeter - delimeter to split by
|
|
// limit if non-zero, maximum times to split text
|
|
// When limited, the remaining text will be left as the last item.
|
|
// E.g. splitting "1,2,3,4,5" with delimeter "," and limit 2 yields this list:
|
|
// "1", "2", "3,4,5"
|
|
|
|
// return value - ds_list containing strings of values
|
|
|
|
var text, delimeter, limit;
|
|
text = argument0;
|
|
delimeter = argument1;
|
|
limit = argument2;
|
|
|
|
var list, count;
|
|
list = ds_list_create();
|
|
count = 0;
|
|
|
|
while (string_pos(delimeter, text) != 0)
|
|
{
|
|
ds_list_add(list, string_copy(text, 1, string_pos(delimeter,text) - 1));
|
|
text = string_copy(text, string_pos(delimeter, text) + string_length(delimeter), string_length(text) - string_pos(delimeter, text));
|
|
|
|
count += 1;
|
|
if (limit and count == limit)
|
|
break;
|
|
}
|
|
ds_list_add(list, text);
|
|
|
|
return list;
|
|
|
|
#define __http_parse_url
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Parses a URL into its components
|
|
// real __http_parse_url(string url)
|
|
|
|
// Return value is a ds_map containing keys for the different URL parts: (or -1 on failure)
|
|
// "url" - the URL which was passed in
|
|
// "scheme" - the URL scheme (e.g. "http")
|
|
// "host" - the hostname (e.g. "example.com" or "127.0.0.1")
|
|
// "port" - the port (e.g. 8000) - this is a real, unlike the others
|
|
// "abs_path" - the absolute path (e.g. "/" or "/index.html")
|
|
// "query" - the query string (e.g. "a=b&c=3")
|
|
// Parts which are not included will not be in the map
|
|
// e.g. http://example.com will not have the "port", "path" or "query" keys
|
|
|
|
// This will *only* work properly for URLs of format:
|
|
// scheme ":" "//" host [ ":" port ] [ abs_path [ "?" query ]]"
|
|
// where [] denotes an optional component
|
|
// file: URLs will *not* work as they lack the authority (host:port) component
|
|
// It will not work correctly for IPv6 host values
|
|
|
|
var url;
|
|
url = argument0;
|
|
|
|
var map;
|
|
map = ds_map_create();
|
|
ds_map_add(map, 'url', url);
|
|
|
|
// before scheme
|
|
var colonPos;
|
|
// Find colon for end of scheme
|
|
colonPos = string_pos(':', url);
|
|
// No colon - bad URL
|
|
if (colonPos == 0)
|
|
return -1;
|
|
ds_map_add(map, 'scheme', string_copy(url, 1, colonPos - 1));
|
|
url = string_copy(url, colonPos + 1, string_length(url) - colonPos);
|
|
|
|
// before double slash
|
|
// remove slashes (yes this will screw up file:// but who cares)
|
|
while (string_char_at(url, 1) == '/')
|
|
url = string_copy(url, 2, string_length(url) - 1);
|
|
|
|
// before hostname
|
|
var slashPos, colonPos;
|
|
// Find slash for beginning of path
|
|
slashPos = string_pos('/', url);
|
|
// No slash ahead - http://host format with no ending slash
|
|
if (slashPos == 0)
|
|
{
|
|
// Find : for beginning of port
|
|
colonPos = string_pos(':', url);
|
|
}
|
|
else
|
|
{
|
|
// Find : for beginning of port prior to /
|
|
colonPos = string_pos(':', string_copy(url, 1, slashPos - 1));
|
|
}
|
|
// No colon - no port
|
|
if (colonPos == 0)
|
|
{
|
|
// There was no slash
|
|
if (slashPos == 0)
|
|
{
|
|
ds_map_add(map, 'host', url);
|
|
return map;
|
|
}
|
|
// There was a slash
|
|
else
|
|
{
|
|
ds_map_add(map, 'host', string_copy(url, 1, slashPos - 1));
|
|
url = string_copy(url, slashPos, string_length(url) - slashPos + 1);
|
|
}
|
|
}
|
|
// There's a colon - port specified
|
|
else
|
|
{
|
|
// There was no slash
|
|
if (slashPos == 0)
|
|
{
|
|
ds_map_add(map, 'host', string_copy(url, 1, colonPos - 1));
|
|
ds_map_add(map, 'port', real(string_copy(url, colonPos + 1, string_length(url) - colonPos)));
|
|
return map;
|
|
}
|
|
// There was a slash
|
|
else
|
|
{
|
|
ds_map_add(map, 'host', string_copy(url, 1, colonPos - 1));
|
|
url = string_copy(url, colonPos + 1, string_length(url) - colonPos);
|
|
slashPos = string_pos('/', url);
|
|
ds_map_add(map, 'port', real(string_copy(url, 1, slashPos - 1)));
|
|
url = string_copy(url, slashPos, string_length(url) - slashPos + 1);
|
|
}
|
|
}
|
|
|
|
// before path
|
|
var queryPos;
|
|
queryPos = string_pos('?', url);
|
|
// There's no ? - no query
|
|
if (queryPos == 0)
|
|
{
|
|
ds_map_add(map, 'abs_path', url);
|
|
return map;
|
|
}
|
|
else
|
|
{
|
|
ds_map_add(map, 'abs_path', string_copy(url, 1, queryPos - 1));
|
|
ds_map_add(map, 'query', string_copy(url, queryPos + 1, string_length(url) - queryPos));
|
|
return map;
|
|
}
|
|
|
|
// Return -1 upon unlikely error
|
|
ds_map_destroy(map);
|
|
return -1;
|
|
|
|
#define __http_resolve_url
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Takes a base URL and a URL reference and applies it to the base URL
|
|
// Returns resulting absolute URL
|
|
// string __http_resolve_url(string baseUrl, string refUrl)
|
|
|
|
// Return value is a string containing the new absolute URL, or "" on failure
|
|
|
|
// Works only for restricted URL syntax as understood by by http_resolve_url
|
|
// The sole restriction of which is that only scheme://authority/path URLs work
|
|
// This notably excludes file: URLs which lack the authority component
|
|
|
|
// As described by RFC3986:
|
|
// URI-reference = URI / relative-ref
|
|
// relative-ref = relative-part [ "?" query ] [ "#" fragment ]
|
|
// relative-part = "//" authority path-abempty
|
|
// / path-absolute
|
|
// / path-noscheme
|
|
// / path-empty
|
|
// However http_resolve_url does *not* deal with fragments
|
|
|
|
// Algorithm based on that of section 5.2.2 of RFC 3986
|
|
|
|
var baseUrl, refUrl;
|
|
baseUrl = argument0;
|
|
refUrl = argument1;
|
|
|
|
// Parse base URL
|
|
var urlParts;
|
|
urlParts = __http_parse_url(baseUrl);
|
|
if (urlParts == -1)
|
|
return '';
|
|
|
|
// Try to parse reference URL
|
|
var refUrlParts, canParseRefUrl;
|
|
refUrlParts = __http_parse_url(refUrl);
|
|
canParseRefUrl = (refUrlParts != -1);
|
|
if (refUrlParts != -1)
|
|
ds_map_destroy(refUrlParts);
|
|
|
|
var result;
|
|
result = '';
|
|
|
|
// Parsing of reference URL succeeded - it's absolute and we're done
|
|
if (canParseRefUrl)
|
|
{
|
|
result = refUrl;
|
|
}
|
|
// Begins with '//' - scheme-relative URL
|
|
else if (string_copy(refUrl, 1, 2) == '//' and string_length(refUrl) > 2)
|
|
{
|
|
result = ds_map_find_value(urlParts, 'scheme') + ':' + refUrl;
|
|
}
|
|
// Is or begins with '/' - absolute path relative URL
|
|
else if (((string_char_at(refUrl, 1) == '/' and string_length(refUrl) > 1) or refUrl == '/')
|
|
// Doesn't begin with ':' and is not blank - relative path relative URL
|
|
or (string_char_at(refUrl, 1) != ':' and string_length(refUrl) > 0))
|
|
{
|
|
// Find '?' for query
|
|
var queryPos;
|
|
queryPos = string_pos('?', refUrl);
|
|
// No query
|
|
if (queryPos == 0)
|
|
{
|
|
refUrl = __http_resolve_path(ds_map_find_value(urlParts, 'abs_path'), refUrl);
|
|
ds_map_replace(urlParts, 'abs_path', refUrl);
|
|
if (ds_map_exists(urlParts, 'query'))
|
|
ds_map_delete(urlParts, 'query');
|
|
}
|
|
// Query exists, split
|
|
else
|
|
{
|
|
var path, query;
|
|
path = string_copy(refUrl, 1, queryPos - 1);
|
|
query = string_copy(refUrl, queryPos + 1, string_length(relUrl) - queryPos);
|
|
path = __http_resolve_path(ds_map_find_value(urlParts, 'abs_path'), path);
|
|
ds_map_replace(urlParts, 'abs_path', path);
|
|
if (ds_map_exists(urlParts, 'query'))
|
|
ds_map_replace(urlParts, 'query', query);
|
|
else
|
|
ds_map_add(urlParts, 'query', query);
|
|
}
|
|
result = __http_construct_url(urlParts);
|
|
}
|
|
|
|
ds_map_destroy(urlParts);
|
|
return result;
|
|
|
|
#define __http_resolve_path
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Takes a base path and a path reference and applies it to the base path
|
|
// Returns resulting absolute path
|
|
// string __http_resolve_path(string basePath, string refPath)
|
|
|
|
// Return value is a string containing the new absolute path
|
|
|
|
// Deals with UNIX-style / paths, not Windows-style \ paths
|
|
// Can be used to clean up .. and . in non-absolute paths too ('' as basePath)
|
|
|
|
var basePath, refPath;
|
|
basePath = argument0;
|
|
refPath = argument1;
|
|
|
|
// refPath begins with '/' (is absolute), we can ignore all of basePath
|
|
if (string_char_at(refPath, 1) == '/')
|
|
{
|
|
basePath = refPath;
|
|
refPath = '';
|
|
}
|
|
|
|
var parts, refParts;
|
|
parts = __http_split(basePath, '/', 0);
|
|
refParts = __http_split(refPath, '/', 0);
|
|
|
|
if (refPath != '')
|
|
{
|
|
// Find last part of base path
|
|
var lastPart;
|
|
lastPart = ds_list_find_value(parts, ds_list_size(parts) - 1);
|
|
|
|
// If it's not blank (points to a file), remove it
|
|
if (lastPart != '')
|
|
{
|
|
ds_list_delete(parts, ds_list_size(parts) - 1);
|
|
}
|
|
|
|
// Concatenate refParts to end of parts
|
|
var i;
|
|
for (i = 0; i < ds_list_size(refParts); i += 1)
|
|
ds_list_add(parts, ds_list_find_value(refParts, i));
|
|
}
|
|
|
|
// We now don't need refParts any more
|
|
ds_list_destroy(refParts);
|
|
|
|
// Deal with '..' and '.'
|
|
for (i = 0; i < ds_list_size(parts); i += 1)
|
|
{
|
|
var part;
|
|
part = ds_list_find_value(parts, i);
|
|
|
|
if (part == '.')
|
|
{
|
|
if (i == 1 or i == ds_list_size(parts) - 1)
|
|
ds_list_replace(parts, i, '');
|
|
else
|
|
ds_list_delete(parts, i);
|
|
i -= 1;
|
|
continue;
|
|
}
|
|
else if (part == '..')
|
|
{
|
|
if (i > 1)
|
|
{
|
|
ds_list_delete(parts, i - 1);
|
|
ds_list_delete(part, i);
|
|
i -= 2;
|
|
}
|
|
else
|
|
{
|
|
ds_list_replace(parts, i, '');
|
|
i -= 1;
|
|
}
|
|
continue;
|
|
}
|
|
else if (part == '' and i != 0 and i != ds_list_size(parts) - 1)
|
|
{
|
|
ds_list_delete(parts, i);
|
|
i -= 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Reconstruct path from parts
|
|
var path;
|
|
path = '';
|
|
for (i = 0; i < ds_list_size(parts); i += 1)
|
|
{
|
|
if (i != 0)
|
|
path += '/';
|
|
path += ds_list_find_value(parts, i);
|
|
}
|
|
|
|
ds_map_destroy(parts);
|
|
return path;
|
|
|
|
#define __http_parse_hex
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Takes a lowercase hexadecimal string and returns its integer value
|
|
// real __http_parse_hex(string hexString)
|
|
|
|
// Return value is the whole number value (or -1 if invalid)
|
|
// Only works for whole numbers (non-fractional numbers >= 0) and lowercase hex
|
|
|
|
var hexString;
|
|
hexString = argument0;
|
|
|
|
var result, hexValues;
|
|
result = 0;
|
|
hexValues = "0123456789abcdef";
|
|
|
|
var i;
|
|
for (i = 1; i <= string_length(hexString); i += 1) {
|
|
result *= 16;
|
|
var digit;
|
|
digit = string_pos(string_char_at(hexString, i), hexValues) - 1;
|
|
if (digit == -1)
|
|
return -1;
|
|
result += digit;
|
|
}
|
|
|
|
return result;
|
|
|
|
#define __http_construct_url
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Constructs an URL from its components (as http_parse_url would return)
|
|
// string __http_construct_url(real parts)
|
|
|
|
// Return value is the string of the constructed URL
|
|
// Keys of parts map:
|
|
// "scheme" - the URL scheme (e.g. "http")
|
|
// "host" - the hostname (e.g. "example.com" or "127.0.0.1")
|
|
// "port" - the port (e.g. 8000) - this is a real, unlike the others
|
|
// "abs_path" - the absolute path (e.g. "/" or "/index.html")
|
|
// "query" - the query string (e.g. "a=b&c=3")
|
|
// Parts which are omitted will be omitted in the URL
|
|
// e.g. http://example.com lacks "port", "path" or "query" keys
|
|
|
|
// This will *only* work properly for URLs of format:
|
|
// scheme ":" "//" host [ ":" port ] [ abs_path [ "?" query ]]"
|
|
// where [] denotes an optional component
|
|
// file: URLs will *not* work as they lack the authority (host:port) component
|
|
// Should work correctly for IPv6 host values, but bare in mind parse_url won't
|
|
|
|
var parts;
|
|
parts = argument0;
|
|
|
|
var url;
|
|
url = '';
|
|
|
|
url += ds_map_find_value(parts, 'scheme');
|
|
url += '://';
|
|
url += ds_map_find_value(parts, 'host');
|
|
if (ds_map_exists(parts, 'port'))
|
|
url += ':' + string(ds_map_find_value(parts, 'port'));
|
|
if (ds_map_exists(parts, 'abs_path'))
|
|
{
|
|
url += ds_map_find_value(parts, 'abs_path');
|
|
if (ds_map_exists(parts, 'query'))
|
|
url += '?' + ds_map_find_value(parts, 'query');
|
|
}
|
|
|
|
return url;
|
|
|
|
#define __http_prepare_request
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Internal function - prepares request
|
|
// void __http_prepare_request(real client, string url, real headers)
|
|
|
|
// client - HttpClient object to prepare
|
|
// url - URL to send GET request to
|
|
// headers - ds_map of extra headers to send, -1 if none
|
|
|
|
var client, url, headers;
|
|
client = argument0;
|
|
url = argument1;
|
|
headers = argument2;
|
|
|
|
var parsed;
|
|
parsed = __http_parse_url(url);
|
|
|
|
if (parsed == -1)
|
|
show_error("Error when making HTTP GET request - can't parse URL: " + url, true);
|
|
|
|
if (!ds_map_exists(parsed, 'port'))
|
|
ds_map_add(parsed, 'port', 80);
|
|
if (!ds_map_exists(parsed, 'abs_path'))
|
|
ds_map_add(parsed, 'abs_path', '/');
|
|
|
|
with (client)
|
|
{
|
|
destroyed = false;
|
|
CR = chr(13);
|
|
LF = chr(10);
|
|
CRLF = CR + LF;
|
|
socket = tcp_connect(ds_map_find_value(parsed, 'host'), ds_map_find_value(parsed, 'port'));
|
|
state = 0;
|
|
errored = false;
|
|
error = '';
|
|
linebuf = '';
|
|
line = 0;
|
|
statusCode = -1;
|
|
reasonPhrase = '';
|
|
responseBody = buffer_create();
|
|
responseBodySize = -1;
|
|
responseBodyProgress = -1;
|
|
responseHeaders = ds_map_create();
|
|
requestUrl = url;
|
|
requestHeaders = headers;
|
|
|
|
// Request = Request-Line ; Section 5.1
|
|
// *(( general-header ; Section 4.5
|
|
// | request-header ; Section 5.3
|
|
// | entity-header ) CRLF) ; Section 7.1
|
|
// CRLF
|
|
// [ message-body ] ; Section 4.3
|
|
|
|
// "The Request-Line begins with a method token, followed by the
|
|
// Request-URI and the protocol version, and ending with CRLF. The
|
|
// elements are separated by SP characters. No CR or LF is allowed
|
|
// except in the final CRLF sequence."
|
|
if (ds_map_exists(parsed, 'query'))
|
|
write_string(socket, 'GET ' + ds_map_find_value(parsed, 'abs_path') + '?' + ds_map_find_value(parsed, 'query') + ' HTTP/1.1' + CRLF);
|
|
else
|
|
write_string(socket, 'GET ' + ds_map_find_value(parsed, 'abs_path') + ' HTTP/1.1' + CRLF);
|
|
|
|
// "A client MUST include a Host header field in all HTTP/1.1 request
|
|
// messages."
|
|
// "A "host" without any trailing port information implies the default
|
|
// port for the service requested (e.g., "80" for an HTTP URL)."
|
|
if (ds_map_find_value(parsed, 'port') == 80)
|
|
write_string(socket, 'Host: ' + ds_map_find_value(parsed, 'host') + CRLF);
|
|
else
|
|
write_string(socket, 'Host: ' + ds_map_find_value(parsed, 'host')
|
|
+ ':' + string(ds_map_find_value(parsed, 'port')) + CRLF);
|
|
|
|
// "An HTTP/1.1 server MAY assume that a HTTP/1.1 client intends to
|
|
// maintain a persistent connection unless a Connection header including
|
|
// the connection-token "close" was sent in the request."
|
|
write_string(socket, 'Connection: close' + CRLF);
|
|
|
|
// "If no Accept-Encoding field is present in a request, the server MAY
|
|
// assume that the client will accept any content coding."
|
|
write_string(socket, 'Accept-Encoding:' + CRLF);
|
|
|
|
// If headers specified
|
|
if (headers != -1)
|
|
{
|
|
var key;
|
|
// Iterate over headers map
|
|
for (key = ds_map_find_first(headers); is_string(key); key = ds_map_find_next(headers, key))
|
|
{
|
|
write_string(socket, key + ': ' + ds_map_find_value(headers, key) + CRLF);
|
|
}
|
|
}
|
|
|
|
// Send extra CRLF to terminate request
|
|
write_string(socket, CRLF);
|
|
|
|
socket_send(socket);
|
|
|
|
ds_map_destroy(parsed);
|
|
}
|
|
|
|
#define __http_parse_header
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Internal function - parses header
|
|
// real __http_parse_header(string linebuf, real line)
|
|
// Returns false if it errored (caller should return and destroy)
|
|
|
|
var linebuf, line;
|
|
linebuf = argument0;
|
|
line = argument1;
|
|
|
|
// "HTTP/1.1 header field values can be folded onto multiple lines if the
|
|
// continuation line begins with a space or horizontal tab."
|
|
if ((string_char_at(linebuf, 1) == ' ' or ord(string_char_at(linebuf, 1)) == 9))
|
|
{
|
|
if (line == 1)
|
|
{
|
|
errored = true;
|
|
error = "First header line of response can't be a continuation, right?";
|
|
return false;
|
|
}
|
|
headerValue = ds_map_find_value(responseHeaders, string_lower(headerName))
|
|
+ string_copy(linebuf, 2, string_length(linebuf) - 1);
|
|
}
|
|
// "Each header field consists
|
|
// of a name followed by a colon (":") and the field value. Field names
|
|
// are case-insensitive. The field value MAY be preceded by any amount
|
|
// of LWS, though a single SP is preferred."
|
|
else
|
|
{
|
|
var colonPos;
|
|
colonPos = string_pos(':', linebuf);
|
|
if (colonPos == 0)
|
|
{
|
|
errored = true;
|
|
error = "No colon in a header line of response";
|
|
return false;
|
|
}
|
|
headerName = string_copy(linebuf, 1, colonPos - 1);
|
|
headerValue = string_copy(linebuf, colonPos + 1, string_length(linebuf) - colonPos);
|
|
// "The field-content does not include any leading or trailing LWS:
|
|
// linear white space occurring before the first non-whitespace
|
|
// character of the field-value or after the last non-whitespace
|
|
// character of the field-value. Such leading or trailing LWS MAY be
|
|
// removed without changing the semantics of the field value."
|
|
while (string_char_at(headerValue, 1) == ' ' or ord(string_char_at(headerValue, 1)) == 9)
|
|
headerValue = string_copy(headerValue, 2, string_length(headerValue) - 1);
|
|
}
|
|
|
|
ds_map_add(responseHeaders, string_lower(headerName), headerValue);
|
|
|
|
if (string_lower(headerName) == 'content-length')
|
|
{
|
|
responseBodySize = real(headerValue);
|
|
responseBodyProgress = 0;
|
|
}
|
|
|
|
return true;
|
|
|
|
#define __http_client_step
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Steps the HTTP client (needs to be called each step or so)
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
with (client)
|
|
{
|
|
if (errored)
|
|
exit;
|
|
|
|
// Socket error
|
|
if (socket_has_error(socket))
|
|
{
|
|
errored = true;
|
|
error = "Socket error: " + socket_error(socket);
|
|
return __http_client_destroy();
|
|
}
|
|
|
|
var available;
|
|
available = tcp_receive_available(socket);
|
|
|
|
switch (state)
|
|
{
|
|
// Receiving lines
|
|
case 0:
|
|
if (!available && tcp_eof(socket))
|
|
{
|
|
errored = true;
|
|
error = "Unexpected EOF when receiving headers/status code";
|
|
return __http_client_destroy();
|
|
}
|
|
|
|
var bytesRead, c;
|
|
for (bytesRead = 1; bytesRead <= available; bytesRead += 1)
|
|
{
|
|
c = read_string(socket, 1);
|
|
// Reached end of line
|
|
// "HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
|
// protocol elements except the entity-body (see appendix 19.3 for
|
|
// tolerant applications)."
|
|
if (c == LF and string_char_at(linebuf, string_length(linebuf)) == CR)
|
|
{
|
|
// Strip trailing CR
|
|
linebuf = string_copy(linebuf, 1, string_length(linebuf) - 1);
|
|
// First line - status code
|
|
if (line == 0)
|
|
{
|
|
// "The first line of a Response message is the Status-Line, consisting
|
|
// of the protocol version followed by a numeric status code and its
|
|
// associated textual phrase, with each element separated by SP
|
|
// characters. No CR or LF is allowed except in the final CRLF sequence."
|
|
var httpVer, spacePos;
|
|
spacePos = string_pos(' ', linebuf);
|
|
if (spacePos == 0)
|
|
{
|
|
errored = true;
|
|
error = "No space in first line of response";
|
|
return __http_client_destroy();
|
|
}
|
|
httpVer = string_copy(linebuf, 1, spacePos);
|
|
linebuf = string_copy(linebuf, spacePos + 1, string_length(linebuf) - spacePos);
|
|
|
|
spacePos = string_pos(' ', linebuf);
|
|
if (spacePos == 0)
|
|
{
|
|
errored = true;
|
|
error = "No second space in first line of response";
|
|
return __http_client_destroy();
|
|
}
|
|
statusCode = real(string_copy(linebuf, 1, spacePos));
|
|
reasonPhrase = string_copy(linebuf, spacePos + 1, string_length(linebuf) - spacePos);
|
|
}
|
|
// Other line
|
|
else
|
|
{
|
|
// Blank line, end of response headers
|
|
if (linebuf == '')
|
|
{
|
|
state = 1;
|
|
// write remainder
|
|
write_buffer_part(responseBody, socket, available - bytesRead);
|
|
responseBodyProgress = available - bytesRead;
|
|
break;
|
|
}
|
|
// Header
|
|
else
|
|
{
|
|
if (!__http_parse_header(linebuf, line))
|
|
return __http_client_destroy();
|
|
}
|
|
}
|
|
|
|
linebuf = '';
|
|
line += 1;
|
|
}
|
|
else
|
|
linebuf += c;
|
|
}
|
|
break;
|
|
// Receiving response body
|
|
case 1:
|
|
write_buffer(responseBody, socket);
|
|
responseBodyProgress += available;
|
|
if (tcp_eof(socket))
|
|
{
|
|
if (ds_map_exists(responseHeaders, 'transfer-encoding'))
|
|
{
|
|
if (ds_map_find_value(responseHeaders, 'transfer-encoding') == 'chunked')
|
|
{
|
|
// Chunked transfer, let's decode it
|
|
var actualResponseBody, actualResponseSize;
|
|
actualResponseBody = buffer_create();
|
|
actualResponseBodySize = 0;
|
|
|
|
// Parse chunks
|
|
// chunk = chunk-size [ chunk-extension ] CRLF
|
|
// chunk-data CRLF
|
|
// chunk-size = 1*HEX
|
|
while (buffer_bytes_left(responseBody))
|
|
{
|
|
var chunkSize, c;
|
|
chunkSize = '';
|
|
|
|
// Read chunk size byte by byte
|
|
while (buffer_bytes_left(responseBody))
|
|
{
|
|
c = read_string(responseBody, 1);
|
|
if (c == CR or c == ';')
|
|
break;
|
|
else
|
|
chunkSize += c;
|
|
}
|
|
|
|
// We found a semicolon - beginning of chunk-extension
|
|
if (c == ';')
|
|
{
|
|
// skip all extension stuff
|
|
while (buffer_bytes_left(responseBody) && c != CR)
|
|
{
|
|
c = read_string(responseBody, 1);
|
|
}
|
|
}
|
|
// Reached end of header
|
|
if (c == CR)
|
|
{
|
|
c += read_string(responseBody, 1);
|
|
// Doesn't end in CRLF
|
|
if (c != CRLF)
|
|
{
|
|
errored = true;
|
|
error = 'header of chunk in chunked transfer did not end in CRLF';
|
|
buffer_destroy(actualResponseBody);
|
|
return __http_client_destroy();
|
|
}
|
|
// chunk-size is empty - something's up!
|
|
if (chunkSize == '')
|
|
{
|
|
errored = true;
|
|
error = 'empty chunk-size in a chunked transfer';
|
|
buffer_destroy(actualResponseBody);
|
|
return __http_client_destroy();
|
|
}
|
|
chunkSize = __http_parse_hex(chunkSize);
|
|
// Parsing of size failed - not hex?
|
|
if (chunkSize == -1)
|
|
{
|
|
errored = true;
|
|
error = 'chunk-size was not hexadecimal in a chunked transfer';
|
|
buffer_destroy(actualResponseBody);
|
|
return __http_client_destroy();
|
|
}
|
|
// Is the chunk bigger than the remaining response?
|
|
if (chunkSize + 2 > buffer_bytes_left(responseBody))
|
|
{
|
|
errored = true;
|
|
error = 'chunk-size was greater than remaining data in a chunked transfer';
|
|
buffer_destroy(actualResponseBody);
|
|
return __http_client_destroy();
|
|
}
|
|
// OK, everything's good, read the chunk
|
|
write_buffer_part(actualResponseBody, responseBody, chunkSize);
|
|
actualResponseBodySize += chunkSize;
|
|
// Check for CRLF
|
|
if (read_string(responseBody, 2) != CRLF)
|
|
{
|
|
errored = true;
|
|
error = 'chunk did not end in CRLF in a chunked transfer';
|
|
return __http_client_destroy();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errored = true;
|
|
error = 'did not find CR after reading chunk header in a chunked transfer, Faucet HTTP bug?';
|
|
return __http_client_destroy();
|
|
}
|
|
// if the chunk size is zero, then it was the last chunk
|
|
if (chunkSize == 0
|
|
// trailer headers will be present
|
|
and ds_map_exists(responseHeaders, 'trailer'))
|
|
{
|
|
// Parse header lines
|
|
var line;
|
|
line = 1;
|
|
while (buffer_bytes_left(responseBody))
|
|
{
|
|
var linebuf;
|
|
linebuf = '';
|
|
while (buffer_bytes_left(responseBody))
|
|
{
|
|
c = read_string(responseBody, 1);
|
|
if (c != CR)
|
|
linebuf += c;
|
|
else
|
|
break;
|
|
}
|
|
c += read_string(responseBody, 1);
|
|
if (c != CRLF)
|
|
{
|
|
errored = true;
|
|
error = 'trailer header did not end in CRLF in a chunked transfer';
|
|
return __http_client_destroy();
|
|
}
|
|
if (!__http_parse_header(linebuf, line))
|
|
return __http_client_destroy();
|
|
line += 1;
|
|
}
|
|
}
|
|
}
|
|
responseBodySize = actualResponseBodySize;
|
|
buffer_destroy(responseBody);
|
|
responseBody = actualResponseBody;
|
|
}
|
|
else
|
|
{
|
|
errored = true;
|
|
error = 'Unsupported Transfer-Encoding: "' + ds_map_find_value(responseHaders, 'transfer-encoding') + '"';
|
|
return __http_client_destroy();
|
|
}
|
|
}
|
|
else if (responseBodySize != -1)
|
|
{
|
|
if (responseBodyProgress < responseBodySize)
|
|
{
|
|
errored = true;
|
|
error = "Unexpected EOF, response body size is less than expected";
|
|
return __http_client_destroy();
|
|
}
|
|
}
|
|
// 301 Moved Permanently/302 Found/303 See Other/307 Moved Temporarily
|
|
if (statusCode == 301 or statusCode == 302 or statusCode == 303 or statusCode == 307)
|
|
{
|
|
if (ds_map_exists(responseHeaders, 'location'))
|
|
{
|
|
var location, resolved;
|
|
location = ds_map_find_value(responseHeaders, 'location');
|
|
resolved = __http_resolve_url(requestUrl, location);
|
|
// Resolving URL didn't fail and it's http://
|
|
if (resolved != '' and string_copy(resolved, 1, 7) == 'http://')
|
|
{
|
|
// Restart request
|
|
__http_client_destroy();
|
|
__http_prepare_request(client, resolved, requestHeaders);
|
|
}
|
|
else
|
|
{
|
|
errored = true;
|
|
error = "301, 302, 303 or 307 response with invalid or unsupported Location URL ('" + location + "') - can't redirect";
|
|
return __http_client_destroy();
|
|
}
|
|
exit;
|
|
}
|
|
else
|
|
{
|
|
errored = true;
|
|
error = "301, 302, 303 or 307 response without Location header - can't redirect";
|
|
return __http_client_destroy();
|
|
}
|
|
}
|
|
else
|
|
state = 2;
|
|
}
|
|
break;
|
|
// Done.
|
|
case 2:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define __http_client_destroy
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Clears up contents of an httpClient prior to destruction or after error
|
|
|
|
if (!destroyed) {
|
|
socket_destroy(socket);
|
|
buffer_destroy(responseBody);
|
|
ds_map_destroy(responseHeaders);
|
|
}
|
|
destroyed = true;
|
|
|
|
#define http_new_get
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Makes a GET HTTP request
|
|
// real http_new_get(string url)
|
|
|
|
// url - URL to send GET request to
|
|
|
|
// Return value is an HttpClient instance that can be passed to
|
|
// fct_http_request_status etc.
|
|
// (errors on failure to parse URL)
|
|
|
|
var url, client;
|
|
|
|
url = argument0;
|
|
|
|
if (!variable_global_exists('__HttpClient'))
|
|
__http_init();
|
|
|
|
client = instance_create(0, 0, global.__HttpClient);
|
|
__http_prepare_request(client, url, -1);
|
|
return client;
|
|
|
|
#define http_new_get_ex
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Makes a GET HTTP request with custom headers
|
|
// real http_new_get_ex(string url, real headers)
|
|
|
|
// url - URL to send GET request to
|
|
// headers - ds_map of extra headers to send
|
|
|
|
// Return value is an HttpClient instance that can be passed to
|
|
// fct_http_request_status etc.
|
|
// (errors on failure to parse URL)
|
|
|
|
var url, headers, client;
|
|
|
|
url = argument0;
|
|
headers = argument1;
|
|
|
|
if (!variable_global_exists('__HttpClient'))
|
|
__http_init();
|
|
|
|
client = instance_create(0, 0, global.__HttpClient);
|
|
__http_prepare_request(client, url, headers);
|
|
return client;
|
|
|
|
#define http_step
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Steps the HTTP client. This is what makes everything actually happen.
|
|
// Call it each step. Returns whether or not the request has finished.
|
|
// real http_step(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
// Return value is either:
|
|
// 0 - In progress
|
|
// 1 - Done or Errored
|
|
|
|
// Example usage:
|
|
// req = http_new_get("http://example.com/x.txt");
|
|
// while (http_step(req)) {}
|
|
// if (http_status_code(req) != 200) {
|
|
// // Errored!
|
|
// } else {
|
|
// // Hasn't errored, do stuff here.
|
|
// }
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
__http_client_step(client);
|
|
|
|
if (client.errored || client.state == 2)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
|
|
#define http_status_code
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Gets the status code
|
|
// real http_status_code(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
// Return value is either:
|
|
// * 0, if the request has not yet finished
|
|
// * a negative value, if there was an internal Faucet HTTP error
|
|
// * a positive value, the status code of the HTTP request
|
|
|
|
// "The Status-Code element is a 3-digit integer result code of the
|
|
// attempt to understand and satisfy the request. These codes are fully
|
|
// defined in section 10. The Reason-Phrase is intended to give a short
|
|
// textual description of the Status-Code. The Status-Code is intended
|
|
// for use by automata and the Reason-Phrase is intended for the human
|
|
// user. The client is not required to examine or display the Reason-
|
|
// Phrase."
|
|
|
|
// See also: http_reason_phrase, gets the Reason-Phrase
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
if (client.errored)
|
|
return -1;
|
|
else if (client.state == 2)
|
|
return client.statusCode;
|
|
else
|
|
return 0;
|
|
|
|
#define http_reason_phrase
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Gets the reason phrase
|
|
// string http_reason_phrase(real client)
|
|
|
|
// client - HttpClient object
|
|
// Return value is either:
|
|
// * "", if the request has not yet finished
|
|
// * an internal Faucet HTTP error message, if there was one
|
|
// * the reason phrase of the HTTP request
|
|
|
|
// "The Status-Code element is a 3-digit integer result code of the
|
|
// attempt to understand and satisfy the request. These codes are fully
|
|
// defined in section 10. The Reason-Phrase is intended to give a short
|
|
// textual description of the Status-Code. The Status-Code is intended
|
|
// for use by automata and the Reason-Phrase is intended for the human
|
|
// user. The client is not required to examine or display the Reason-
|
|
// Phrase."
|
|
|
|
// See also: http_status_code, gets the Status-Code
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
if (client.errored)
|
|
return client.error;
|
|
else if (client.state == 2)
|
|
return client.reasonPhrase;
|
|
else
|
|
return "";
|
|
|
|
#define http_response_body
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Gets the response body returned by an HTTP request as a buffer
|
|
// real http_response_body(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
// Return value is a buffer if client hasn't errored and is finished
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
return client.responseBody;
|
|
|
|
#define http_response_body_size
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Gets the size of response body returned by an HTTP request
|
|
// real http_response_body_size(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
// Return value is the size in bytes, or -1 if we don't know or don't know yet
|
|
|
|
// Call this each time you use the size - it may have changed in the case of redirect
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
return client.responseBodySize;
|
|
|
|
#define http_response_body_progress
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Gets the size of response body returned by an HTTP request which is so far downloaded
|
|
// real http_response_body_progress(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
// Return value is the size in bytes, or -1 if we haven't started yet or client has errored
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
return client.responseBodyProgress;
|
|
|
|
#define http_response_headers
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Gets the response headers returned by an HTTP request as a ds_map
|
|
// real http_response_headers(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
// Return value is a ds_map if client hasn't errored and is finished
|
|
|
|
// All headers will have lowercase keys
|
|
// The ds_map is owned by the HttpClient, do not use ds_map_destroy() yourself
|
|
// Call when the request has finished - otherwise may be incomplete or missing
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
return client.responseHeaders;
|
|
|
|
#define http_destroy
|
|
// ***
|
|
// This function forms part of Faucet HTTP v1.0
|
|
// https://github.com/TazeTSchnitzel/Faucet-HTTP-Extension
|
|
//
|
|
// Copyright (c) 2013-2014, Andrea Faulds <ajf@ajf.me>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
// ***
|
|
|
|
// Cleans up HttpClient
|
|
// void http_destroy(real client)
|
|
|
|
// client - HttpClient object
|
|
|
|
var client;
|
|
client = argument0;
|
|
|
|
with (client)
|
|
{
|
|
__http_client_destroy();
|
|
instance_destroy();
|
|
}
|
|
|