/
uri.go
75 lines (64 loc) · 1.51 KB
/
uri.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package main
import (
"crypto/sha1"
"errors"
"fmt"
"net/url"
"strings"
)
var (
errNoBtih = errors.New("Magnet URI xt parameter missing the 'urn:btih:' prefix. Not a bittorrent hash link?")
)
type Magnet struct {
InfoHashes []string
Names []string
}
func parseMagnet(s string) (mag Magnet, err error) {
// References:
// - http://bittorrent.org/beps/bep_0009.html
// - http://en.wikipedia.org/wiki/Magnet_URI_scheme
//
// Example bittorrent magnet link:
//
// => magnet:?xt=urn:btih:bbb6db69965af769f664b6636e7914f8735141b3&dn=Ubuntu-12.04-desktop-i386.iso
//
// xt: exact topic.
// ~ urn: uniform resource name.
// ~ btih: bittorrent infohash.
// dn: display name (optional).
// tr: address tracker (optional).
u, err := url.Parse(s)
if err != nil {
return
}
xts, ok := u.Query()["xt"]
if !ok {
err = errors.New(fmt.Sprintf("Magnet URI missing the 'xt' argument: %s", s))
return
}
infoHashes := make([]string, 0, len(xts))
for _, xt := range xts {
s := strings.Split(xt, "urn:btih:")
if len(s) != 2 {
err = errNoBtih
return
}
ih := s[1]
// TODO: support base32 encoded hashes, if they still exist.
if len(ih) != sha1.Size*2 { // hex format.
err = errors.New(fmt.Sprintf("Magnet URI contains infohash with unexpected length. Wanted %d, got %d: %v", sha1.Size, len(ih), ih))
return
}
infoHashes = append(infoHashes, s[1])
}
var names []string
n, ok := u.Query()["dn"]
if ok {
names = n
}
mag = Magnet{
InfoHashes: infoHashes,
Names: names,
}
return
}