summaryrefslogtreecommitdiff
path: root/ot_http.c
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-27 03:07:41 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-10-27 03:07:41 +0100
commitdb3a0b9bb51ba59051173b0f81f1d088a5176d95 (patch)
tree463404abfa2636b1ac59a06027ab23819f0d39ec /ot_http.c
parent90e265483c1c73aed67ea4b8bce2b825c04d656a (diff)
Sort info_hashes in a scrape so that the reply forms a valid bencoded dict
Diffstat (limited to 'ot_http.c')
-rw-r--r--ot_http.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/ot_http.c b/ot_http.c
index 14952b5..2216453 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -24,6 +24,7 @@
24#include "ot_scan.h" 24#include "ot_scan.h"
25#include "ot_event.h" 25#include "ot_event.h"
26#include "ot_fdstate.h" 26#include "ot_fdstate.h"
27#include "ot_vector.h"
27#include "ot_fmt.h" 28#include "ot_fmt.h"
28#include "ot_stats.h" 29#include "ot_stats.h"
29#include "ot_urlencoded.h" 30#include "ot_urlencoded.h"
@@ -233,7 +234,6 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
233 {"scrp", TASK_STATS_SCRAPE}, 234 {"scrp", TASK_STATS_SCRAPE},
234 {"udp4", TASK_STATS_UDP}, 235 {"udp4", TASK_STATS_UDP},
235 {"tcp4", TASK_STATS_TCP}, 236 {"tcp4", TASK_STATS_TCP},
236 {"busy", TASK_STATS_BUSY_NETWORKS},
237 {"torr", TASK_STATS_TORRENTS}, 237 {"torr", TASK_STATS_TORRENTS},
238 {"fscr", TASK_STATS_FULLSCRAPE}, 238 {"fscr", TASK_STATS_FULLSCRAPE},
239 {"s24s", TASK_STATS_SLASH24S}, 239 {"s24s", TASK_STATS_SLASH24S},
@@ -418,13 +418,15 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *
418} 418}
419#endif 419#endif
420 420
421static int compare_hash(const void *left, const void *right) { return memcmp(left, right, sizeof(ot_hash)); }
422
421static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { 423static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) {
422 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; 424 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}};
423 425
424 ot_hash *multiscrape_buf = (ot_hash *)ws->request; 426 ot_hash *multiscrape_buf = (ot_hash *)ws->request;
425 char *reply = ws->reply; 427 char *reply = ws->reply;
426 int scanon = 1; 428 int scanon = 1;
427 size_t numwant = 0; 429 size_t i, unique, numwant = 0;
428 430
429 /* This is to hack around stupid clients that send "scrape ?info_hash" */ 431 /* This is to hack around stupid clients that send "scrape ?info_hash" */
430 if (read_ptr[-1] != '?') { 432 if (read_ptr[-1] != '?') {
@@ -461,6 +463,14 @@ static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws,
461 if (numwant > OT_MAXMULTISCRAPE_COUNT) 463 if (numwant > OT_MAXMULTISCRAPE_COUNT)
462 numwant = OT_MAXMULTISCRAPE_COUNT; 464 numwant = OT_MAXMULTISCRAPE_COUNT;
463 465
466 /* A bencoded dictionary has its keys in order and names each one once, so
467 the answer cannot just follow the order the client asked in */
468 qsort(multiscrape_buf, numwant, sizeof(ot_hash), compare_hash);
469 for (i = unique = 1; i < numwant; ++i)
470 if (memcmp(multiscrape_buf[i], multiscrape_buf[unique - 1], sizeof(ot_hash)))
471 memcpy(multiscrape_buf[unique++], multiscrape_buf[i], sizeof(ot_hash));
472 numwant = unique;
473
464 /* Enough for http header + whole scrape string */ 474 /* Enough for http header + whole scrape string */
465 return_tcp_scrape_for_torrent((const ot_hash *)multiscrape_buf, numwant, &reply, ws->outbuf + G_OUTBUF_SIZE); 475 return_tcp_scrape_for_torrent((const ot_hash *)multiscrape_buf, numwant, &reply, ws->outbuf + G_OUTBUF_SIZE);
466 ws->reply_size = reply - ws->reply; 476 ws->reply_size = reply - ws->reply;