将Torrent info_hash从bencoded转换为URLEncoded数据

时间:2012-08-10 03:08:38

标签: objective-c ios http afnetworking bittorrent

我在objective-c中创建了torrent scraper,我正在使用AFNetworking来处理HTTP请求。我需要发送跟踪器请求的元信息部分的sha1哈希值。我已成功创建哈希并验证它是否正确。我不能将哈希值放在NSString中,因为它不对二进制数据进行编码,因此我将其放在NSData对象中,然后在要发送的参数中。这就是我现在所拥有的,但我总是得到一个错误,我会假设它是使用我用来发送哈希的方法。我也尝试过对url进行编码,然后将其放入NSString中,但无效

 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 个答案:

答案 0 :(得分:4)

好吧,我不是种子专家,但我认为你所遇到的挑战是你所提取的 bencoded 数据表示将SHA1哈希编码为20个原始字节数据

您无法在HTTP请求的GET部分中发送类似的原始数据,因此您需要对其进行编码。根据规范,似乎 urlencoding 原始数据是官方的方式。 (其他选项是将其转换为人类可读的十六进制字符串,例如)。

从此Alternative Bittorrent Specification

  

跟踪器是HTTP / HTTPS服务,它响应HTTP GET请求。请求包括来自客户端的指标,这些指标可帮助跟踪器保留有关torrent的整体统计信息。响应包括帮助客户端参与torrent的对等列表。基本URL由metainfo(.torrent)文件中定义的“通告URL”组成。然后使用标准CGI方法将参数添加到此URL(即在声明URL之后为'?',后跟由'&'分隔的'param = value'序列)。

     

请注意,必须正确转义URL中的所有二进制数据(特别是info_hash和peer_id)。这意味着任何不在集合0-9,az,AZ,'。',' - ','_'和'〜'中的字节必须使用“%nn”格式进行编码,其中nn是十六进制值字节。 (有关详细信息,请参阅RFC1738。)

     

对于\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a

的20字节哈希      

正确的编码形式为%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A

从原始的20 char C数组开始,您需要访问 URLEncoded NSString

不幸的是,特别是对于这种类型的数据,简单的方法 - 在循环中使用stringByAddingPercentEscapesUsingEncoding将无法工作,因为它不会以安全编码结束作为GET参数发送。

有一点S.O. help(How do I URL encode a string),这里有一些代码,你可以在最终产品中使用,但符合规范文档以获得正确的输出:

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
祝你好运!