Split Requests
Warning
Split requests should not be used for public-facing applications. No protections are provided that would result in out-of-memory errors from malicious requests.
Split requests intended to be used for cases where a lot of data needs to be transferred via POST requests, and this amount of data may be beyond what the client can send or recieve, like Roblox Studio.
Protocol
The protocol is able to have split requests and split responses. For this example, a client is only able to send 6 characters in the body and the server is configured to only send back 4 characters. The POST body sent is then echoed back without modification.
Standalone
If no split-request parameters are speicifed, the request is treated as non-split and the response is sent back complete.
POST http://localhost:8080 "Test1 Test2 Test3" HTTP 200 "Test1 Test2 Test3"
This implementation allows for clients without needing to get around limits to not need to use the implementation, such as external end-to-end testing of applications.
Sending Split Requests
Split requests take data as URL arguments, which include the following:
- maxPackets
- The total packets that will be sent
- requestId
- The id of the packet to send (not sent in the first request)
- packet
- The id of the pakcet to send, starting at 0 (optional in the first request)
When a request is incomplete (not all packets sent), a JSON
string is returned with the following
- status
- "incomplete"
- id
- The value to use in requestId
to continue the request
When a response is complete, the following is returned:
- status
- "success"
- id
- The value to use in responseId
for getting responses
- currentPacket
- The id of the packet, starting at 0.
- maxPackets
- The total packets to recieve
- packet
- The data in the pakcet
For getting additional responses (maxPackets > 1), the following
arguments can be used:
- getResponse = true
- Specifies that responses are being fetched
- responseId
- The response id to read from
- packet
- The packet id to get from the response, starting at 0
For the example above, the requests would look like the following:
POST http://localhost:8080?maxPackets=3 "Test1 " HTTP 200 "{"status\":\"incomplete\",\"id\":0}" POST http://localhost:8080?maxPackets=3&packet=1&requestId=0 "Test2 " HTTP 200 "{"status\":\"incomplete\",\"id\":0}" POST http://localhost:8080?maxPackets=3&packet=2&requestId=0 "Test 3" HTTP 200 "{"status\":\"success\",\"id\":0,\"currentPacket\":0,\"maxPackets\":4 \"packet\":\"Test1\"}" GET http://localhost:8080?getResponse=true&responseId=0&packet=1 "Test 3" HTTP 200 "{"status\":\"success\",\"id\":0,\"currentPacket\":1,\"maxPackets\":4,\"packet\":\" Tes\"}" GET http://localhost:8080?getResponse=true&responseId=0&packet=2 "Test 3" HTTP 200 "{"status\":\"success\",\"id\":0,\"currentPacket\":2,\"maxPackets\":4,\"packet\":\"t2 T\"}" GET http://localhost:8080?getResponse=true&responseId=0&packet=3 "Test 3" HTTP 200 "{"status\":\"success\",\"id\":0,\"currentPacket\":3,\"maxPackets\":4,\"packet\":\"est3\"}"
After a response is fully retrieved, it is removed to save memory. This however does cause a vulnerability since malicous (or just incorrect usage of the protocol) will result in a memory leak. Same goes for sending requests since they need to be stored and combined. Additionally, there is no checks for the size, so denial of service attacks can be performed by sending large, incomplete requests that won't get cleared. This system is not intended for publicly facing applications.
Code Example
The code from the previous example can be tweaked to work with this (ignoring
the limit of sending back 4 characters) by using the base class SplitClientRequestHandler
for the client handler and using SplitRequestHandler
which ensures that
the GET
handlers are added.
using Nexus.Http.Server.Http.Request; using Nexus.Http.Server.Http.Response; using Nexus.Http.Server.Http.Server; using Nexus.Http.Server.SplitHttp.Request; namespace Demo { public class Program { public class Handler : SplitClientRequestHandler { /* * Returns a response for a given complete request. */ public override HttpResponse GetCompleteResponseData(HttpRequest request) { return HttpResponse.CreateSuccessResponse(request.GetBody()); } } public static void Main(string[] args) { // Create the request handlers. var handler = new SplitRequestHandler(); handler.RegisterHandler("POST","/",new Handler()); handler.RegisterHandler("POST","/test",new Handler()); // Create and start the server. var server = new HttpServer(8080,handler); server.Start(); } } }