Recently, the Internet Engineering Task Force aka the IETF approved a new HTTP verb, QUERY.
The basic idea behind QUERY is that it's a parameterless GET with a body like a POST. Or more specifically, you take all of those parameters that you were putting on the URL and instead put them in the body of your request.
Why?
Because in the Year of Our Lord 2026, it turns out that a GET request can have a lot of parameters and/or the parameters can be sufficiently long enough to exceed the character limit of browsers or web servers. But request bodies–like those of POST can be a lot longer.
The HTTP server has a few responsibilities when it comes to handling QUERY queries. For example, the content type specified in the Content-Type HTTP header has to match the actual content type of the body. If the two don't match, the server is supposed to reject the the QUERY's query. And QUERY is to be idempotent. For those of you from Redmond, that means identical QUERY calls should get identical responses every time. In theory, this means that QUERY requests should be cashable, but, as I suspect is always the case with these sorts of things, the devil is in the details.
So it's all well and good that the IETF still finds itself useful and that the HTTP protocol still has room to grow. But so what?
Well, because PacketSender now has QUERY support built into it. I know it does because I added the functionality. A public release with this functionality should be imminently forthcoming, but as a contributor to the Open Source project and not the maintainer of the project, I can't give a hard release date. I can, however, tell you that there has been even more functionality added to PacketSender since I added QUERY, but that's for another post.
What I do want to talk about are some of the decisions I made while adding the QUERY functionality to PacketSender.
sendCustomRequest()
When Dan Nagel, maintainer of PacketSender reached out to me and told me of the new HTTP verb, we both thought it should be relatively easy to implement because Qt's QNetworkAccessManager has overloads on sendCustomRequest() that can take any HTTP verb. And when I say any, I mean any. Even ones that hadn't been approved prior to Qt writing their code.
The tricky part was supporting headers.
And this is where I reveal one of my many flaws.
At first, I thought that PacketSender didn't support HTTP headers because I didn't see a place to set them. But, just like with light mode/dark mode, I didn't know there was a setting...because I didn't look in Settings.
It turns out there is a whole panel related to HTTP headers in Settings:
Prior to adding QUERY, PacketSender had a setting where it would try to set the Content-Type HTTP header automagically by looking at the stating and ending characters. This was enough to make a reasonable inference of whether the content type was JSON or XML. But this only worked on POST requests...which isn't unreasonable given that I recently added support for PUT, PATCH and DELETE and was unaware of the setting.
Dan and I decided to have the setting apply to all posts with bodies; this means QUERY was added to the list; DELETE has an optional body, so the logic is, unsurprisingly, conditionally applied to DELETE.
At the time of this writing, HTTP headers are not per packet, but rather per domain. This makes sense from the standpoint that you can only send one packet at a time: therefore, do you really need to edit the header to send the same packet a second time? And if you're sending a packet to the same domain as the previous packet, well, you're going to have to change the data in the main window. Even if you had a space to add or edit headers in the main window, you'd still have to change that data, so, really, is PacketSender asking too much?
I was and am torn on this issue. But thinking it through logically, what's really annoying is that you have to open a modal dialog to edit the headers.
Headers button
I wanted to save the user some pain, so I added a Headers button to the main window. Adding the physical(?) Qt's Designer app was a straightforward drag and drop. Thankfully, the main window had room to accommodate the button.
Because I care about the user, I wanted to save them clicks. I didn't just want the Settings window to open, I wanted it to open to the HTTP tab. That was accomplished with this line of code:
Settings settings(this);
settings.setCurrentTab("HTTP"); // or whatever the tab name/index is
int accepted = settings.exec();
(oops, I didn't delete the comment)
I'm staggered that worked the first time I tried it, especially since I didn't read the existing code and didn't know if there were names for the tabs.
Warning the user
Remember earlier when I said that the server is supposed to reject QUERY requests if the Content-Type header and the actual content type of the body didn't match? Well, I wanted to warn the user about that.
Now, I came up as an Automated Tester in this industry. As such, I care about the user's experience. I wanted to warn them if they tried to send a QUERY with an empty body. Initially, following a traffic-light metaphor of green for success, orange for warning and red for errors, I put an orange border around the data field on the main window and flashed it four times, once per second if an empty data field was submitted. I also put a warning text on the main window. (PacketSender's idiom for this is text in the bottom, left-hand corner.)
Dan didn't like the attention grabbing of the flashing border. And, to be fair, the text I put on the dialog was a bit long and you couldn't read it in the four seconds. So I got rid of the flashing data field, shorted the text, but this time made the text orange. Dan still didn't like the visual, so ultimately the orange text came out.
Command line support
Something I didn't mention in my previous post was that PUT, PATCH and DELETE are also supported on the command line in PacketSender. The reason I didn't mention it in my previous post was I hadn't implemented CLI support at the time of writing and didn't know what it was going to take to support those verbs. It turned out to not require that much effort once one understood the flow of the logic.
Looking back, I don't remember much other than thinking "it'd be nice to simplify this code so I don't have to have an if statement for every verb. So I came up with the map idea.
But we can't really support QUERY on the command line yet because PacketSender doesn't support custom headers on the command line at all. So, we could auto-guess on the body type and add a Content-Type header which might cover enough cases, but that's too much magic that the user can't override. Instead, I've created an issue. PRs are welcome of course, but I'd be more than happy to accept donations to implement the feature.
I'm proud that I was able to read the RFC and understand the work that needed to be done. I'm grateful for the work that Dan did years ago to have enough framework and implementation in place that I could mostly add glue code.
If you found anything useful in this post or want to support continued improvements to PacketSender, you can donate via PayPal.
I’m also open to new opportunities; feel free to reach out.




Top comments (0)