Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

After upgrade to qBittorrent v4.5.0, now get BadRequest when I delete torrents through API #18097

Open
briankitt opened this issue Nov 29, 2022 · 35 comments · May be fixed by jerrymakesjelly/autoremove-torrents#187
Labels
WebAPI WebAPI-related issues/changes

Comments

@briankitt
Copy link

briankitt commented Nov 29, 2022

qBittorrent & operating system versions

qBittorrent: 4.5.0 x64, official build from website, no mods of any type
Operating system: Windows 10 Pro 21H2 build 19044.2251 (10.0.19044)

What is the problem?

This worked fine on prior version (unknown version, I last upgraded 2 months ago, so whatever version that was)

Here is my code. I've tried both POST and GET. It should be POST, per documentation, but I've tried GET to cover bases.
Again, this worked perfectly yesterday. I upgraded to v4.5.0 today, and now it fails with 'BadRequest' every time.
I can delete this torrent just fine from the qBittorrent console

       var method = HttpMethod.Post;
       var url = "http://127.0.0.1:8080/api/v2/torrents/delete?hashes=a6383161d63323a7cef9606c0769374a3b047d54&deleteFiles=false";

        using (var myRequest = new HttpRequestMessage(method, url)
        {
            var myResponse = await httpClient.SendAsync(myRequest);
            if (myResponse.IsSuccessStatusCode)
            {
                using (var myStream = new MemoryStream())
                {
                    myResponse.Content.ReadAsStream().CopyTo(myStream);

                    return Encoding.Default.GetString(myStream.ToArray());
                }
            }
            else
            {
                return $"{myResponse.StatusCode} - {myResponse.ReasonPhrase} on {apiName}/{methodName}{query} method {method.Method}";
            }
        }

Steps to reproduce

It's an API that I wrote. I shared the code above. Not sure what else I can do?

Additional context

I'd be happy to share logs or any additional info if needed, please ask.

Log(s) & preferences file(s)

Nothing sensitive in here.
Config.zip

(N) 2022-11-29T00:47:08 - Enqueued torrent move. Torrent: "SomeFile". Source: "D:\BT\qInProgress". Destination: "D:\BT\Completed"
(N) 2022-11-29T00:47:08 - Start moving torrent. Torrent: "SomeFile". Destination: "D:\BT\Completed"
(N) 2022-11-29T00:47:09 - Moved torrent successfully. Torrent: "SomeFile". Destination: "D:\BT\Completed"
(N) 2022-11-29T00:47:09 - Torrent download finished. Torrent: "SomeFile"
(N) 2022-11-29T00:47:09 - Running external program. Torrent: "SomeFile". Command: d:\bt\PlexBatch\PlexWorker.Batch.exe TorrentFinished "SomeFile" "D:\BT\Completed\SomeFile" "SomeFile" "D:\BT\Completed" "a6383161d63323a7cef9606c0769374a3b047d54" "-" "a6383161d63323a7cef9606c0769374a3b047d54"

Inside of PlexWorker.Batch.Exe, I do the call above, which results in the BadRequest error
There is NOTHING in the log indicating anything to do with my API delete.

@depuytnl
Copy link

I have the same issue

@thalieht thalieht added the WebAPI WebAPI-related issues/changes label Nov 29, 2022
@grtgh
Copy link

grtgh commented Dec 2, 2022

I have a similar issue. I have posted the details on case# 18132

@jobrien2001
Copy link

jobrien2001 commented Dec 3, 2022

+1

Same problem

Getting Method not allowed

Switching to post worked for me

curl -d "hashes=$HASH&deleteFiles=true" -X POST "$QBITURL/api/v2/torrents/delete" --cookie "$COOKIE"

@glassez
Copy link
Member

glassez commented Dec 3, 2022

Starting with v4.5 many WebAPI endpoints were restricted to POST method only.

@francisdidden
Copy link

Indeed, I had the same issue and changed it to a post with the parameters in the body.

Powershell code example:
$hashesToDeleteString = "1a61bb4aeec95bdb9bb1082c67d24cc1bf66009c|1a61bb4aeec95bdb9bb1082c67d24cc1bf660045"
$body = @{
"hashes"=$hashesToDeleteString
"deleteFiles"="false"
}
Invoke-RestMethod -Uri "http://localhost:8080/api/v2/torrents/delete" -Method Post -Body $body

@briankitt
Copy link
Author

briankitt commented Dec 3, 2022 via email

@hstorey219
Copy link

url = 'api/v2/torrents/delete?hashes='+str(tor['hash'])+'&deleteFiles=true'

Sorry, how would I code this to use POST?

@briankitt
Copy link
Author

briankitt commented Dec 3, 2022 via email

@hstorey219
Copy link

That depends on the language you use. POST v GET is a 'method' used to transfer data from your app to the server (qBittorrent in this case). There are many methods, including PATCH, DELETE, etc. You would always specify a method in the transfer. As a 'for example', I use C#. The method is the first parameter I pass. new HttpRequestMessage(method,

On Sat, Dec 3, 2022 at 4:10 PM Harry Storey @.> wrote: url = 'api/v2/torrents/delete?hashes='+str(tor['hash'])+'&deleteFiles=true' Sorry, how would I code this to use POST? — Reply to this email directly, view it on GitHub <#18097 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAXDH6FI2JMGHPFVQI5QYSTWLPALTANCNFSM6AAAAAASN4SFUE . You are receiving this because you authored the thread.Message ID: @.>

Sorry I am using Python script

@briankitt
Copy link
Author

briankitt commented Dec 3, 2022 via email

@briankitt
Copy link
Author

briankitt commented Dec 3, 2022 via email

@hstorey219
Copy link

Here's an explanation of how a POST is done. https://www.w3schools.com/python/ref_requests_post.asp On Sat, Dec 3, 2022 at 4:15 PM Harry Storey @.> wrote:

That depends on the language you use. POST v GET is a 'method' used to transfer data from your app to the server (qBittorrent in this case). There are many methods, including PATCH, DELETE, etc. You would always specify a method in the transfer. As a 'for example', I use C#. The method is the first parameter I pass. new HttpRequestMessage(method, … <#m_-7651487754727070193_> On Sat, Dec 3, 2022 at 4:10 PM Harry Storey @.
> wrote: url = 'api/v2/torrents/delete?hashes='+str(tor['hash'])+'&deleteFiles=true' Sorry, how would I code this to use POST? — Reply to this email directly, view it on GitHub <#18097 (comment) <#18097 (comment)>>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAXDH6FI2JMGHPFVQI5QYSTWLPALTANCNFSM6AAAAAASN4SFUE https://github.com/notifications/unsubscribe-auth/AAXDH6FI2JMGHPFVQI5QYSTWLPALTANCNFSM6AAAAAASN4SFUE . You are receiving this because you authored the thread.Message ID: @.
> Sorry I am using Python script — Reply to this email directly, view it on GitHub <#18097 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAXDH6CMF742E7AJBYGQIBDWLPA7RANCNFSM6AAAAAASN4SFUE . You are receiving this because you authored the thread.Message ID: @.
**>

Thank you!

@grtgh
Copy link

grtgh commented Dec 5, 2022

thanks everyone. c#: moving from GET to POST worked for me:
{
bc = new FormUrlEncodedContent(
{
new KeyValuePair<string, string>("hashes", hash),
new KeyValuePair<string, string>("deleteFiles", "false")
});
hrm = hc.PostAsync("/api/v2/torrents/delete", bc).Result;
result = hrm.Content.ReadAsStringAsync.Result;
if (hrm.IsSuccessStatusCode)
pass = true;
}

@briankitt
Copy link
Author

briankitt commented Dec 6, 2022 via email

@jobrien2001
Copy link

I would presume you donnt have authentication because you didnt pass a cookie?

Did you try a simple curl request just to test? or something like postman?

Im not familiar with the language.

@briankitt
Copy link
Author

briankitt commented Dec 6, 2022 via email

@jobrien2001
Copy link

Whats odd is that you were getting a bad request error...

I think we were all getting "method not allowed". Bad request would mean something is malformed?

I would start looking at running something simple like curl like i suggested before, just to test things out.

@glassez
Copy link
Member

glassez commented Dec 6, 2022

var method = HttpMethod.Post;
var url = "http://127.0.0.1:8080/api/v2/torrents/delete?hashes=a6383161d63323a7cef9606c0769374a3b047d54&deleteFiles=false";

Doesn't seem like correct thing. Is query string allowed to be in URL when method is POST?

@briankitt
Copy link
Author

briankitt commented Dec 6, 2022 via email

@hstorey219
Copy link

Did anyone get this working with python?

@briankitt
Copy link
Author

briankitt commented Dec 10, 2022 via email

@hoangduc67
Copy link

same problem when I send with GET method that server return Method Not Allowed. When I change into POST then it said Bad Request, I already change to DELETE still bad request. I am using Postman with Authend is off

@glassez
Copy link
Member

glassez commented Dec 30, 2022

@qbittorrent/bug-handlers
Could someone investigate it?

@D-Walter
Copy link

D-Walter commented Jan 14, 2023

Because qbittorrent try reading data from body instead of query. In my case, this code block is working:

import urllib
req = urllib.request.Request(
        url="http://host:port/api/v2/torrents/pause",
        method="POST",
        data=urllib.parse.urlencode({"hashes": "your_hashes"}).encode(encoding="utf8"),
        headers={"Content-Type": "application/x-www-form-urlencoded"},
    )

and delete torrent:

req = urllib.request.Request(
        url="http://host:port/api/v2/torrents/delete",
        method="POST",
        data=urllib.parse.urlencode({"hashes": "your_hashes", "deleteFiles": "false"}).encode(encoding="utf8"),
        headers={"Content-Type": "application/x-www-form-urlencoded"},
    )

@briankitt
Copy link
Author

briankitt commented Jan 17, 2023 via email

@glassez
Copy link
Member

glassez commented Jan 17, 2023

Works fine with built-in webUI.

@D-Walter
Copy link

D-Walter commented Jan 17, 2023 via email

@briankitt
Copy link
Author

briankitt commented Jan 27, 2023 via email

@Arathen
Copy link

Arathen commented Feb 11, 2023

Thank you @briankitt for working this out. You have also solved this problem for me. The WebAPI documentation for pause and resume operations is also outdated and incorrect. Changing the pause/resume API calls to use form variables works.

eg:

HASHSTR="hash1|hash2|hash3"
curl -v -b "SID=${SID}" -X POST -F "hashes=${HASHSTR}" http://${QBTHOST}/api/v2/torrents/pause
curl -v -b "SID=${SID}" -X POST -F "hashes=${HASHSTR}" http://${QBTHOST}/api/v2/torrents/resume

@Dreamray
Copy link

Dreamray commented Feb 14, 2023

I have the same issue, I using Javascript ajax on tampermonkey of chrome, the browser console displays: 400 (Bad Request)
my code is:

let url = '/api/v2/torrents/delete?hashes=xxxxxxxxxx&deleteFiles=true',
    xhrDelete = new XMLHttpRequest();
xhrDelete.open('POST', url, true);
xhrDelete.send();
xhrDelete.onreadystatechange = function () {
    if(xhrDelete.readyState == 4 && ((xhrDelete.status >= 200 && xhrDelete.status < 300) || xhrDelete.status == 304)){
        some code...
    }
}

update:
Today I change my code to jQuery ajax, it worked and I don't know why.

@thiDucTran
Copy link

Thank you @briankitt for working this out. You have also solved this problem for me. The WebAPI documentation for pause and resume operations is also outdated and incorrect. Changing the pause/resume API calls to use form variables works.

eg:

HASHSTR="hash1|hash2|hash3"
curl -v -b "SID=${SID}" -X POST -F "hashes=${HASHSTR}" http://${QBTHOST}/api/v2/torrents/pause
curl -v -b "SID=${SID}" -X POST -F "hashes=${HASHSTR}" http://${QBTHOST}/api/v2/torrents/resume

Thanks! fixed my pause/resume html 405 issue

@kafisatz
Copy link

I can confirm this works as post request.
I am on qBittorrent 4.5.5.
Here is a curl example which works for me (including cookie for authentication)
curl -X POST http://10.14.15.205:8080/api/v2/torrents/delete -d "hashes=a4bc314b5286d4b2caa4552ffb6b98b0998a1f36&deleteFiles=true" --cookie "SID=1321h6STVBiIbvdKDOtICxzFtzpnFLdo"

@Feriman22
Copy link

I had same issue, but @jobrien2001 solution worked for me. So use the curl like this:

curl -d "hashes=$HASH&deleteFiles=true" -X POST "$QBITURL/api/v2/torrents/delete" --cookie "$COOKIE"

Instead of this:

curl -X POST '$QBITURL/api/v2/torrents/delete?hashes=$HASH&deleteFiles=true' --cookie "$COOKIE"

@dmitryrn
Copy link

dmitryrn commented Jan 12, 2024

I think for Delete you have to specify deleteFiles=false or true to make it work.

@kafisatz
Copy link

@dmitryrn you are correct. thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WebAPI WebAPI-related issues/changes
Projects
None yet
Development

Successfully merging a pull request may close this issue.