Преобразовать торрент информация закодированный хэш от данных в кодировке url


Я создаю торрент-скребок в objective-c и использую AFNetworking для HTTP-запросов. Мне нужно отправить sha1 хэш части мета-информации для запроса трекера. Я успешно создал хэш и проверил, что он правильный. Я не могу поместить хэш в NSString, так как он не кодирует двоичные данные, поэтому я поместил его в объект NSData, а затем в параметры для отправки. Это то, что у меня есть прямо сейчас, но я всегда получаю ошибку обратно, и я бы предположил это это с методами, которые я использую для отправки хэша. Я также попытался кодировать url-адрес хэша, а затем поместить его в строку NS безрезультатно

 NSMutableDictionary *parameters = [NSMutableDictionary dictionary];

 unsigned char infoHash[20];
 [self.tracker generateTorrentInfoHash:infoHash];

 const char peer_id[20] = "randomstringfornow";

[parameters setObject:[NSData dataWithBytes:&infoHash length:20] forKey:@"info_hash"];    
[parameters setObject:[NSData dataWithBytes:&peer_id length:20] forKey:@"peer_id"];
[parameters setObject:@(8080) forKey:@"port"];
[parameters setObject:@(0) forKey:@"uploaded"];
[parameters setObject:@(self.tracker.metaInfo.totalFileSize) forKey:@"left"];
[parameters setObject:@(0) forKey:@"downloaded"];
[parameters setObject:@(0) forKey:@"compact"];
[parameters setObject:@"stopped" forKey:@"event"];


[self getPath:@"" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"%@",operation.responseString);


   } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"%@",operation.responseString);
}];

Кто-нибудь знает, есть ли возможный способ сделать это с помощью AFNetworking, или, возможно, я надеюсь, что упускаю что-то простое.

1 6

1 ответ:

Хорошо, я не эксперт по торрентам, но я думаю, что проблема, с которой вы столкнулись, заключается в том, что представление данных bencoded, которое вы извлекаете, кодирует хэш SHA1 как 20 необработанных байт данных.

Вы не можете отправить такие необработанные данные в GET-части HTTP-запроса, поэтому вам нужно будет их закодировать. Основываясь на спецификациях, кажется, что urlencoding необработанные данные являются официальным способом сделать это. (Другими вариантами было бы преобразовать его в читаемую человеком шестнадцатеричную строку, например).

Из этой альтернативной спецификации Bittorrent :

Трекер-это служба HTTP / HTTPS, которая отвечает на запросы HTTP GET. Запросы включают метрики от клиентов, которые помогают трекеру вести общую статистику о торренте. Ответ включает в себя список одноранговых узлов, который помогает клиенту участвовать в потоке. Базовый URL-адрес состоит из "объявить URL", как определено в metainfo (.торрент-файл. Затем к этому добавляются параметры URL, используя стандартные методы CGI (то есть a '? после сообщить URL-адрес, с последующим последовательностей Параметр=Значение, разделенных символом '&').

Обратите внимание, что все двоичные данные в URL (особенно info_hash и peer_id) должны быть правильно экранированы. Это означает любой байт, не входящий в набор 0-9, a-z, A-Z,'.', '- ', '_' и'~', должны быть закодированы с использованием формата "%nn", где nn-шестнадцатеричное значение байта. (Подробности смотрите в RFC1738.)

Для 20-байтового хэша \x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a

Справа кодированная форма %124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A

Начиная с вашего массива raw 20 char C, вам нужно добраться до URLEncoded NSString.

К сожалению, особенно с этим типом данных, простой метод - использование stringByAddingPercentEscapesUsingEncoding в цикле - не будет работать, потому что он не заканчивается безопасной кодировкой для отправки в качестве параметра GET.

С помощью бита S. O. help (How do I URL encode a string ), вот немного кода, который вы можете сформировать в конечный продукт, но соответствует спецификации doc для правильный вывод:

const char source[20] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9a};

NSMutableString *output = [NSMutableString string];

NSLog(@"Raw Data: %@", [NSData dataWithBytes:source length:20]);

int sourceLen = sizeof(source);

for (int i = 0; i < sourceLen; ++i) {
    const unsigned char thisChar = source[i];
    if (thisChar == ' '){
        [output appendString:@"+"];
    } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' || 
               (thisChar >= 'a' && thisChar <= 'z') ||
               (thisChar >= 'A' && thisChar <= 'Z') ||
               (thisChar >= '0' && thisChar <= '9')) {
        [output appendFormat:@"%c", thisChar];
    } else {
        [output appendFormat:@"%%%02X", thisChar];
    }
}

NSLog(@"Encoded:  %@", output);

Вывод:

Raw Data: <12345678 9abcdef1 23456789 abcdef12 3456789a>
Encoded:  %124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A

Удачи!