bencode

package module
v0.0.0-...-a0f8ea5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2023 License: MIT Imports: 6 Imported by: 3

README

Bencode

A fast and secure Go library to encode and parse Bencode.

Inspired by the great work done by @jackpal/bencode-go and @marksamman/bencode.

Examples

Here are some usage examples:

import "github.com/stefanovazzocell/bencode"

// Parse a string
bencode.NewParserFromString("10:helloworld").AsString() // "helloworld", nil
// Parse an object
bencode.NewParserFromString("d4:name5:Alice3:agei35ee").AsInterface() // map[string]{}{ "name": "Alice", "age": 35 }, nil

// Parse a map from an io.Reader
// fileReader implements io.Reader and returns "li1ei2ei3ee"
bencode.NewParserFromReader(fileReader).AsList() // []interface{1, 2, 3}


// Encode an object
encoder, err := bencode.NewEncoderFromInterface([]interface{}{1,2,3})
if err != nil {
    // TODO: Handle error
}
encoder.String() // "li1ei2ei3ee"

Aims

As per the introduction I aim to make this library fast and secure. Here I will address how I plan to achieve those goals.

Secure

Since this library contains a parser that might be used to read user-generated content it's important for it to be well tested.

  • Near-100% code coverage (make test, coverage: up_to* 96.1%).
  • Extensively fuzzed (make fuzz, coverage: 99.3%).
  • Checked for security issues with gosec (make security).
  • No external dependencies

*up_to: one of the tests uses an intentionally unreliable io.Reader.

Performance

This library needs to perform well as it might need to encode/decode a large amount of data efficiently. Benchmarks are available with make bench.

$ make bench
go test -run=^$ -cover -bench .
goos: linux
goarch: amd64
pkg: github.com/stefanovazzocell/bencode
cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
BenchmarkEncoder/torrentString-12               13454383        88.96 ns/op
BenchmarkEncoder/complexMap-12                   1384812       867.4 ns/op
BenchmarkReaderParser/complexMap-12               545340      1873 ns/op
BenchmarkReaderParser/torrentString-12           3972987       329.2 ns/op
BenchmarkReaderParser/torrentStringAsString-12   4413070       269.6 ns/op
BenchmarkStringParser/complexMap-12               730975      1386 ns/op
BenchmarkStringParser/torrentString-12          14311644        77.85 ns/op
BenchmarkStringParser/torrentStringAsString-12  26242033        42.01 ns/op

Furthermore you can profile specific components with the following:

  • make profileEncoder
  • make profileStringParser

Caveats

There are some things to consider

  • This library can encode int and uint as well as all their variations (i.e.: int64, uint16, ...) but it can only parse numbers of type int.
  • This library can only encode maps of type map[string]interface{} and slices of type []interface{}.
  • Additional data after the initial parse will be ignored, unless another parse operation (such as .AsList()) is called on the same parser.
  • When parsing io.Reader strings are limited to ~8MB of size max.

Documentation

Index

Constants

View Source
const (
	MaxStringLength = 2 << 22 // ~ 8MB
)

Variables

View Source
var (
	// Error for when the user tries to read a specific type of bencode
	// but the bencode doesn't provide that type
	ErrInvalidType = errors.New("invalid bencode output type")
	// Error indicating an invalid string length such as "-1:"
	ErrInvalidStringLen = errors.New("invalid bencode: string length can't be negative")
)
View Source
var (
	// Only called by panic() when n, _ = io.Reader.Read(); n < 0
	ErrNegativeRead = errors.New("readerParser: reader returned a negative read")
	// Error returned if a string length is larger than 8MB (to avoid this use stringParser instead)
	ErrLargeStringLen = errors.New("readerParser: string length are limited to ~8MB for security reasons")
)

Functions

func NewEncoderFromInt

func NewEncoderFromInt(i int64) *encoder

Returns a bencode encoder from a given int64

func NewEncoderFromInterface

func NewEncoderFromInterface(v interface{}) (*encoder, error)

Returns a bencode encoder from a given object

func NewEncoderFromMap

func NewEncoderFromMap(m map[string]interface{}) (*encoder, error)

Returns a bencode encoder from a given map[string]interface{}

func NewEncoderFromSlice

func NewEncoderFromSlice(l []interface{}) (*encoder, error)

Returns a bencode encoder from a given slice

func NewEncoderFromString

func NewEncoderFromString(s string) *encoder

Returns a bencode encoder from a given string

func NewEncoderFromUint

func NewEncoderFromUint(u uint64) *encoder

Returns a bencode encoder from a given int64

func NewParserFromReader

func NewParserFromReader(reader io.Reader) *decoder

Returns a bencode decoder from a given string

func NewParserFromString

func NewParserFromString(bencode string) *decoder

Returns a bencode decoder from a given string

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL