Page 1 of 1

HTTP 400 bad request on /command/setForceStart in WebUI API

Posted: Wed May 16, 2018 6:07 pm
by mavaddat
I am trying to write a Powershell script to automatically force resume certain torrents. However, I am having trouble reaching the /command/setForceStart endpoint with the Invoke-WebRequest module.
Here is my script at the relevant part:

Code: Select all

$r = @()
$dest = ls $env:TEMP\  -Filter Any_HnR_Ts* | where -EQ "Directory" -Property Attributes
$torrents = Get-ChildItem -Path $dest.FullName -Filter *.torrent
$r += Invoke-WebRequest -Uri "http://localhost:8080/login" -WebSession $my_session -Headers @{Referer="http://localhost:8080"} -Method Post -UserAgent "Fiddler" -ContentType "application/x-www-form-urlencoded" -Body "username=mavaddat&password="
[System.Reflection.Assembly]::LoadFrom("C:\Users\mavad\Documents\WindowsPowerShell\Modules\BencodeNET\BencodeNET.dll")
$h=@()
foreach ($torrent in $torrents){
   $h += Get-Hash -Algorithm SHA1 -StringEncoding utf8 -InputObject $(([BencodeNET.Parsing.BencodeParser]::new().Parse($torrent.FullName)['info']).EncodeAsBytes())
   $r += Invoke-WebRequest -Uri 'http://localhost:8080/command/resume' -WebSession $my_session -UserAgent 'Fiddler' -Method Post -ContentType 'application/x-www-form-urlencoded' -Body "hash=$($h.ToString())"
   }
$r += Invoke-WebRequest -Uri 'http://localhost:8080/command/setForceStart' -WebSession $my_session -UserAgent 'Fiddler' -Method Post -ContentType 'application/x-www-form-urlencoded' -Body ("hashes={0}`?value=true" -f $($h -join "|"))
This should get a list of all the torrents to resume (targets), log into the WebUI landing page, then individually soft resume each target torrent, and finally force start all the target torrents.
However, the attempt to force start returns a 400 bad request with the following web response:

IsMutuallyAuthenticated False
Cookies {SID=wxbQZkcVRPSJwpO4o91JZ3x03j6gzTd2}
Headers
connectionkeep-alivecontent-security-policydefault-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; object-src 'none';x-content-type-optionsnosniffx-frame-optionsSAMEORIGINx-xss-protection1; mode=blockContent-Length0DateWed, 16 May 2018 17:47:43 GMTSet-CookieSID=wxbQZkcVRPSJwpO4o91JZ3x03j6gzTd2; HttpOnly; path=/

SupportsHeaders True
ContentLength 0
ContentEncoding
ContentType
CharacterSet
Server
LastModified 2018-05-16 10:49:13 AM
StatusCode BadRequest
StatusDescription Bad Request
ProtocolVersion 1.1
ResponseUri http://localhost:8080/command/setForceStart
Method POST
IsFromCache False

Does anyone know what I might be doing wrong?
Please note I am using BencodeNET to parse the torrent files, which does correctly parse them. Then I calculate the SHA1 hash for each torrent using the bytes of the torrent info, which also correctly derives their hashes (in uppercase base64). I've tried converting them to lowercase without any difference in the result.
I am currently running the latest qBitTorrent v4.1.0 x64 with Qt: 5.10.1 Libtorrent: 1.1.7.0 Boost: 1.67.0
Also, I have verified that the hashes I am looking for are valid. So I notice that the WebUI API documentation says
[quote="WebUI API documentation"]If your torrent hash is invalid, the server will reply with:

Code: Select all

HTTP/1.1 404 Not Found
[/quote]
but I don't think this should apply.
To verify my hashes, I have run this example:

Code: Select all

$info = Invoke-WebRequest -Uri "http://localhost:8080/api/v2/torrents/info?category=Books" -WebSession $my_session -UserAgent Fiddler -Method Get | ConvertFrom-Json
foreach ($book in $info) {if ($book.hash -eq $h[0]){$book.name}}
These two commands will return the correct book title for the given hash (i.e., the first hash computed in my list as stored in $h[0]).
A more thorough examination of each hash (in the code below) shows that every computed hash matches some torrent in my list:

Code: Select all

$info = Invoke-WebRequest -Uri "http://localhost:8080/api/v2/torrents/info?category=Books" -WebSession $my_session -UserAgent Fiddler -Method Get | ConvertFrom-Json
foreach ($hash in $h) {foreach ($book in $info) {if ($book.hash -eq $hash){$found = $book.name}}; Write-Host $found; Remove-Variable -Name found }
This nested for-loop will test every hash against every torrent listed by the WebUI API and it successfully verifies every hash without any errors or exceptions.
More simply, this set difference will return no results:

Code: Select all

$h.HashString | ?{ -not $info.hash -contains $_}