href-multipart (#29448)

This commit is contained in:
jellyveggie2
2021-05-06 10:31:13 +02:00
committed by GitHub
parent 765cac5c1b
commit b1b7cad795
4 changed files with 126 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
/*
* ==== HREF multipart handler ====
* For situations where your Topic() link exceeds the browser's ~2000 character limit and ends up ignored
*
* Give your atom a handler, specifying said atom as the handler's parent on New(), and have your atom's Topic() be redirected to
* the handler if the href contains the 'multipart=1' parameter.
* An example would look like this:
*
* /obj/foo
* var/datum/href_multipart_handler/mp_handler
*
* /obj/foo/New()
* ..()
* mp_handler = new /datum/href_multipart_handler(src)
* ...
*
* /obj/foo/Topic(href, href_list)
* if (href_list["multipart"])
* mp_handler.Topic(href, href_list)
* else
*
* On your UI's headers, import href_multipart_handler.js and have your submit link pass it's href through 'HREFmultipartHandler()'
* (See '/code/modules/html_interface/href_multipart_handler.js' for more info)
*
*
* == How it works ==
* As explained, the parent atom's Topic() receives a multipart request that is redirected to this handler.
*
* This request contains the following parameters:
* - src: As with all Topic() links, specifies the object that'll handle the request
* - multipart: Specifies that this is a multipart request. Will always be '1'
* - multipart-total: Specifies how many more requests to expect
* - multipart-number: Specifies which part this is, so that all parts may be reassembled in order
* - multipart-content: The actual payload, percent encoded. The parameters you were trying to send but had to be sliced up.
*
* Each part's multipart-content is stored in an array, sorted by multipart-number as there's a risk parts may arrive out of order. Once
* all parts have been received the array's contents are pieced together, decoded, and used to call the parent atom's Topic().
*
*/
/datum/href_multipart_handler
var/atom/parent
var/list/parts
/datum/href_multipart_handler/New(parent)
..()
src.parent = parent
/datum/href_multipart_handler/Destroy()
..()
parent = null
parts = null
/datum/href_multipart_handler/Topic(href, href_list)
if(href_list["multipart"])
// Initialize the list to the size specified by 'multipart-total'
if (!parts)
parts = new /list(text2num(href_list["multipart-total"]))
// Store the part we've received
parts[text2num(href_list["multipart-number"])] = href_list["multipart-content"]
// Check wether we've received all parts
var/complete = 1
for (var/i = 1; i <= parts.len && complete; i++)
complete = complete && parts[i]
// If we've received the complete set, piece it all together and pass the resulting parameters back to our parent object's Topic()
if (complete)
var/content = "";
for (var/c in parts)
content += c
content = url_decode(content)
parts = null
parent.Topic(content, params2list(content))

View File

@@ -0,0 +1,45 @@
/* ==== HREF MULTIPART HANDLER ====
*
* For situations where your Topic() link exceeds the browser's ~2000 character limit and ends up ignored.
*
* Import this file in your UI's headers. Leave your link's href empty, instead have it pass the object's reference (the "src=" parameter)
* and your parameters to 'HREFmultipartHandler(topicSrc, rawContent)'.
* An example might look like this:
*
* <a onclick='HREFmultipartHandler(src, "foo=aaaa...aaaa;bar=aaaa...aaaa");'
*
* The object that'll handle the Topic() should have an href_multipart_handler, and redirect multipart requests ('multipart=1' parameter) towards
* said handler's Topic (See '/code/modules/html_interface/href_multipart_handler.dm' for more info).
*
* == How it works ==
* Your parameter string is percent encoded, and split into 'N' pieces, each at most 'MULTIPART_PART_SIZE' characters (that is, less than 2000 characters).
*
* Each piece is sent as an individual request (simulating clincking a link), alongside with the following parameters:
* - src: As with all Topic() links, specifies the object that'll handle the request
* - multipart: Specifies that this is a multipart request. Will always be '1'
* - multipart-total: Specifies how many parts to expect ('N' pieces)
* - multipart-number: Specifies which part this is, so that all parts may be reassembled in order
* - multipart-content: The actual payload, percent encoded. The parameters you were trying to send but had to be sliced up.
*/
/* Limit is specified at 2048 characters (http://support.microsoft.com/kb/208427), base multipart link will usually be at least ~84 characters.
* 1900 should provides leeway for 32 digit part requests. WAY more than enough, hopefully
*/
const MULTIPART_PART_SIZE = 1900;
function HREFmultipartHandler(topicSrc, rawContent) {
//Sanitize our payload and calculate how many parts will be needed
var content = encodeURIComponent(rawContent);
var totalParts = Math.ceil(content.length/MULTIPART_PART_SIZE);
//Prepare the href's parameters
var baseMultipartParams = "?src=" + topicSrc + ";multipart=1;multipart-total=" + totalParts + ";multipart-number=";
//Slice the content into parts and send each part
for (var part = 0; part < totalParts; part++) {
var contentPart = content.slice(MULTIPART_PART_SIZE * part, MULTIPART_PART_SIZE * (part + 1));
window.location.href = baseMultipartParams + (part + 1) + ";multipart-content=" + contentPart;
}
}