Browse Source

Update dependencies

DarthSim 7 years ago
parent
commit
3224221372
100 changed files with 9950 additions and 655 deletions
  1. 8 4
      glide.lock
  2. 3 0
      glide.yaml
  3. 1 1
      vendor/github.com/h2non/bimg/.editorconfig
  4. 1 0
      vendor/github.com/h2non/bimg/.gitignore
  5. 9 6
      vendor/github.com/h2non/bimg/.travis.yml
  6. 44 0
      vendor/github.com/h2non/bimg/History.md
  7. 3 2
      vendor/github.com/h2non/bimg/README.md
  8. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_1.jpg
  9. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_1_out.jpg
  10. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_2.jpg
  11. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_2_out.jpg
  12. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_3.jpg
  13. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_3_out.jpg
  14. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_4.jpg
  15. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_4_out.jpg
  16. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_5.jpg
  17. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_5_out.jpg
  18. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_6.jpg
  19. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_6_out.jpg
  20. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_7.jpg
  21. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_7_out.jpg
  22. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_8.jpg
  23. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Landscape_8_out.jpg
  24. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_1.jpg
  25. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_1_out.jpg
  26. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_2.jpg
  27. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_2_out.jpg
  28. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_3.jpg
  29. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_3_out.jpg
  30. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_4.jpg
  31. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_4_out.jpg
  32. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_5.jpg
  33. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_5_out.jpg
  34. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_6.jpg
  35. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_6_out.jpg
  36. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_7.jpg
  37. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_7_out.jpg
  38. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_8.jpg
  39. BIN
      vendor/github.com/h2non/bimg/fixtures/exif/Portrait_8_out.jpg
  40. BIN
      vendor/github.com/h2non/bimg/fixtures/test_gif.jpg
  41. BIN
      vendor/github.com/h2non/bimg/fixtures/test_pdf.jpg
  42. BIN
      vendor/github.com/h2non/bimg/fixtures/test_svg.jpg
  43. BIN
      vendor/github.com/h2non/bimg/fixtures/transparent_trim.png
  44. 7 0
      vendor/github.com/h2non/bimg/image.go
  45. 22 2
      vendor/github.com/h2non/bimg/image_test.go
  46. 3 0
      vendor/github.com/h2non/bimg/options.go
  47. 7 552
      vendor/github.com/h2non/bimg/resize.go
  48. 10 0
      vendor/github.com/h2non/bimg/resize_legacy.go
  49. 572 0
      vendor/github.com/h2non/bimg/resizer.go
  50. 60 0
      vendor/github.com/h2non/bimg/resizer_test.go
  51. 5 3
      vendor/github.com/h2non/bimg/type_test.go
  52. 1 1
      vendor/github.com/h2non/bimg/version.go
  53. 57 13
      vendor/github.com/h2non/bimg/vips.go
  54. 29 12
      vendor/github.com/h2non/bimg/vips.h
  55. 8 1
      vendor/github.com/h2non/bimg/vips_test.go
  56. 27 15
      vendor/golang.org/x/image/vector/raster_floating.go
  57. 54 43
      vendor/golang.org/x/image/vector/vector_test.go
  58. 10 0
      vendor/golang.org/x/net/.gitattributes
  59. 2 0
      vendor/golang.org/x/net/.gitignore
  60. 3 0
      vendor/golang.org/x/net/AUTHORS
  61. 31 0
      vendor/golang.org/x/net/CONTRIBUTING.md
  62. 3 0
      vendor/golang.org/x/net/CONTRIBUTORS
  63. 27 0
      vendor/golang.org/x/net/LICENSE
  64. 22 0
      vendor/golang.org/x/net/PATENTS
  65. 3 0
      vendor/golang.org/x/net/README
  66. 41 0
      vendor/golang.org/x/net/bpf/asm.go
  67. 218 0
      vendor/golang.org/x/net/bpf/constants.go
  68. 82 0
      vendor/golang.org/x/net/bpf/doc.go
  69. 704 0
      vendor/golang.org/x/net/bpf/instructions.go
  70. 525 0
      vendor/golang.org/x/net/bpf/instructions_test.go
  71. 10 0
      vendor/golang.org/x/net/bpf/setter.go
  72. 1 0
      vendor/golang.org/x/net/bpf/testdata/all_instructions.bpf
  73. 79 0
      vendor/golang.org/x/net/bpf/testdata/all_instructions.txt
  74. 140 0
      vendor/golang.org/x/net/bpf/vm.go
  75. 512 0
      vendor/golang.org/x/net/bpf/vm_aluop_test.go
  76. 192 0
      vendor/golang.org/x/net/bpf/vm_bpf_test.go
  77. 49 0
      vendor/golang.org/x/net/bpf/vm_extension_test.go
  78. 174 0
      vendor/golang.org/x/net/bpf/vm_instructions.go
  79. 380 0
      vendor/golang.org/x/net/bpf/vm_jump_test.go
  80. 246 0
      vendor/golang.org/x/net/bpf/vm_load_test.go
  81. 115 0
      vendor/golang.org/x/net/bpf/vm_ret_test.go
  82. 247 0
      vendor/golang.org/x/net/bpf/vm_scratch_test.go
  83. 144 0
      vendor/golang.org/x/net/bpf/vm_test.go
  84. 1 0
      vendor/golang.org/x/net/codereview.cfg
  85. 54 0
      vendor/golang.org/x/net/context/context.go
  86. 583 0
      vendor/golang.org/x/net/context/context_test.go
  87. 74 0
      vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
  88. 29 0
      vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
  89. 147 0
      vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
  90. 79 0
      vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
  91. 105 0
      vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
  92. 72 0
      vendor/golang.org/x/net/context/go17.go
  93. 20 0
      vendor/golang.org/x/net/context/go19.go
  94. 300 0
      vendor/golang.org/x/net/context/pre_go17.go
  95. 109 0
      vendor/golang.org/x/net/context/pre_go19.go
  96. 31 0
      vendor/golang.org/x/net/context/withtimeout_test.go
  97. 210 0
      vendor/golang.org/x/net/dict/dict.go
  98. 132 0
      vendor/golang.org/x/net/dns/dnsmessage/example_test.go
  99. 1997 0
      vendor/golang.org/x/net/dns/dnsmessage/message.go
  100. 1116 0
      vendor/golang.org/x/net/dns/dnsmessage/message_test.go

+ 8 - 4
glide.lock

@@ -1,17 +1,21 @@
-hash: de73486dba2fd32ca4e577ba7baa1552e33431fa2a88c1f34ba9b7af77e9c75b
-updated: 2017-07-06T01:19:28.013165848+06:00
+hash: 54db290c0c5bcd14e69e3faa4a1a23040d9117283134d96d6d8ed0df3544283e
+updated: 2017-09-15T13:31:21.075317146+03:00
 imports:
 - name: github.com/h2non/bimg
-  version: 32e459e416aa4abab45ba854298602cb9682256d
+  version: 276e0541892a9c518de3cf332536cd30ebef25de
 - name: github.com/tj/go-debug
   version: ff4a55a20a86994118644bbddc6a216da193cc13
 - name: golang.org/x/image
-  version: 426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d
+  version: e20db36d77bd0cb36cea8fe49d5c37d82d21591f
   subpackages:
   - riff
   - vp8
   - vp8l
   - webp
+- name: golang.org/x/net
+  version: 859d1a86bb617c0c20d154590c3c5d3fcb670b07
+  subpackages:
+  - netutil
 - name: gopkg.in/yaml.v2
   version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b
 testImports: []

+ 3 - 0
glide.yaml

@@ -3,3 +3,6 @@ import:
 - package: github.com/h2non/bimg
   version: ~1.0.9
 - package: gopkg.in/yaml.v2
+- package: golang.org/x/net
+  subpackages:
+  - netutil

+ 1 - 1
vendor/github.com/h2non/bimg/.editorconfig

@@ -1,7 +1,7 @@
 root = true
 
 [*]
-indent_style = tabs
+indent_style = tab
 indent_size = 2
 end_of_line = lf
 charset = utf-8

+ 1 - 0
vendor/github.com/h2non/bimg/.gitignore

@@ -6,3 +6,4 @@ bin
 /*.webp
 /fixtures/*_out.*
 /.idea/
+fixtures/test_vertical_*.jpg

+ 9 - 6
vendor/github.com/h2non/bimg/.travis.yml

@@ -7,14 +7,16 @@ go:
   - 1.6
   - 1.7
   - 1.8
+  - 1.9
   - tip
 
 env:
   - LIBVIPS=7.42.3
   - LIBVIPS=8.2.3
   - LIBVIPS=8.3.3
-  - LIBVIPS=8.4.5
-  - LIBVIPS=8.5.6
+  - LIBVIPS=8.4.6
+  - LIBVIPS=8.5.8
+  - LIBVIPS=8.6.0-alpha4
   - LIBVIPS=master
 
 matrix:
@@ -22,6 +24,7 @@ matrix:
     - env: LIBVIPS=7.42.3
     - env: LIBVIPS=8.2.3
     - env: LIBVIPS=8.3.3
+    - env: LIBVIPS=8.6.0-alpha4
 
 cache:
   apt:
@@ -48,15 +51,15 @@ addons:
 # VIPS 8.3.3 requires Poppler 0.30 which is not released on Trusty.
 before_install:
   - >
-    test "$LIBVIPS" != "master" -a "$LIBVIPS" \< "8.5" \
+    test "$LIBVIPS" != "master" -a "$LIBVIPS" \< "8.4" \
         && wget http://www.vips.ecs.soton.ac.uk/supported/${LIBVIPS%.*}/vips-${LIBVIPS}.tar.gz -O vips.tgz \
         || echo ":-)"
   - >
-    test "$LIBVIPS" != "master" -a "$LIBVIPS" \> "8.5" \
-        && wget https://github.com/jcupitt/libvips/releases/download/v${LIBVIPS}/vips-${LIBVIPS}.tar.gz -O vips.tgz \
+    test "$LIBVIPS" != "master" -a "$LIBVIPS" \> "8.4" \
+        && wget https://github.com/jcupitt/libvips/archive/v${LIBVIPS}.tar.gz -O vips.tgz \
         || echo ":-)"
   - >
-    test $LIBVIPS == "master"\
+    test $LIBVIPS == "master" \
         && wget https://github.com/jcupitt/libvips/archive/${LIBVIPS}.tar.gz -O vips.tgz \
         || echo ":-)"
   - mkdir libvips

+ 44 - 0
vendor/github.com/h2non/bimg/History.md

@@ -1,4 +1,48 @@
 
+## v1.0.14 / 2017-09-12
+
+  * Merge pull request #192 from greut/trim
+  * Adding trim operation.
+  * Merge pull request #191 from greut/alpha4
+  * Update 8.6 to alpha4.
+
+## v1.0.13 / 2017-09-11
+
+  * Merge pull request #190 from greut/typos
+  * Fix typo and small cleanup.
+
+## v1.0.12 / 2017-09-10
+
+  * Merge branch '99designs-vips-reduce'
+  * fix(reduce): resolve conflicts with master
+  * Use vips reduce when downscaling
+
+## v1.0.11 / 2017-09-10
+
+  * feat(#189): allow strip image metadata via bimg.Options.StripMetadata = bool
+  * fix(resize): code format issue
+  * refactor(resize): add Go version comment
+  * refactor(tests): fix minor code formatting issues
+  * fix(#162): garbage collection fix. split Resize() implementation for Go runtime specific
+  * feat(travis): add go 1.9
+  * Merge pull request #183 from greut/autorotate
+  * Proper handling of the EXIF cases.
+  * Merge pull request #184 from greut/libvips858
+  * Merge branch 'master' into libvips858
+  * Merge pull request #185 from greut/libvips860
+  * Add libvips 8.6 pre-release
+  * Update to libvips 8.5.8
+  * fix(resize): runtime.KeepAlive is only Go
+  * fix(#159): prevent buf to be freed by the GC before resize function exits
+  * Merge pull request #171 from greut/fix-170
+  * Check the length before jumping into buffer.
+  * Merge pull request #168 from Traum-Ferienwohnungen/icc_transform
+  * Add option to convert embedded ICC profiles
+  * Merge pull request #166 from danjou-a/patch-1
+  * Fix Resize verification value
+  * Merge pull request #165 from greut/libvips846
+  * Testing using libvips8.4.6 from Github.
+
 ## v1.0.10 / 2017-06-25
 
   * Merge pull request #164 from greut/length

+ 3 - 2
vendor/github.com/h2non/bimg/README.md

@@ -35,7 +35,7 @@ If you're using `gopkg.in`, you can still rely in the `v0` without worrying abou
 
 - Resize
 - Enlarge
-- Crop (including smart crop support)
+- Crop (including smart crop support, libvips 8.5+)
 - Rotate (with auto-rotate based on EXIF orientation)
 - Flip (with auto-flip based on EXIF metadata)
 - Flop
@@ -47,6 +47,7 @@ If you're using `gopkg.in`, you can still rely in the `v0` without worrying abou
 - Custom output color space (RGB, grayscale...)
 - Format conversion (with additional quality/compression settings)
 - EXIF metadata (size, alpha channel, profile, orientation...)
+- Trim (libvips 8.6+)
 
 ## Prerequisites
 
@@ -132,7 +133,7 @@ if err != nil {
 }
 
 size, err := bimg.NewImage(newImage).Size()
-if size.Width == 400 && size.Height == 300 {
+if size.Width == 800 && size.Height == 600 {
   fmt.Println("The image size is valid")
 }
 

BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_1.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_1_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_2.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_2_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_3.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_3_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_4.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_4_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_5.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_5_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_6.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_6_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_7.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_7_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_8.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Landscape_8_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_1.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_1_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_2.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_2_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_3.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_3_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_4.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_4_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_5.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_5_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_6.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_6_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_7.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_7_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_8.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/exif/Portrait_8_out.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/test_gif.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/test_pdf.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/test_svg.jpg


BIN
vendor/github.com/h2non/bimg/fixtures/transparent_trim.png


+ 7 - 0
vendor/github.com/h2non/bimg/image.go

@@ -178,6 +178,13 @@ func (i *Image) Colourspace(c Interpretation) ([]byte, error) {
 	return i.Process(options)
 }
 
+// Trim removes the background from the picture. It can result in a 0x0 output
+// if the image is all background.
+func (i *Image) Trim() ([]byte, error) {
+	options := Options{Trim: true}
+	return i.Process(options)
+}
+
 // Process processes the image based on the given transformation options,
 // talking with libvips bindings accordingly and returning the resultant
 // image buffer.

+ 22 - 2
vendor/github.com/h2non/bimg/image_test.go

@@ -457,8 +457,8 @@ func TestFluentInterface(t *testing.T) {
 
 func TestImageSmartCrop(t *testing.T) {
 
-	if !(VipsMajorVersion >= 8 && VipsMinorVersion > 4) {
-		t.Skipf("Skipping this test, libvips doesn't meet version requirement %s > 8.4", VipsVersion)
+	if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 5) {
+		t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.5", VipsVersion)
 	}
 
 	i := initImage("northern_cardinal_bird.jpg")
@@ -475,6 +475,26 @@ func TestImageSmartCrop(t *testing.T) {
 	Write("fixtures/test_smart_crop.jpg", buf)
 }
 
+func TestImageTrim(t *testing.T) {
+
+	if !(VipsMajorVersion >= 8 && VipsMinorVersion >= 6) {
+		t.Skipf("Skipping this test, libvips doesn't meet version requirement %s >= 8.6", VipsVersion)
+	}
+
+	i := initImage("transparent.png")
+	buf, err := i.Trim()
+	if err != nil {
+		t.Errorf("Cannot process the image: %#v", err)
+	}
+
+	err = assertSize(buf, 250, 208)
+	if err != nil {
+		t.Errorf("The image wasn't trimmed.")
+	}
+
+	Write("fixtures/transparent_trim.png", buf)
+}
+
 func TestImageLength(t *testing.T) {
 	i := initImage("test.jpg")
 

+ 3 - 0
vendor/github.com/h2non/bimg/options.go

@@ -204,6 +204,8 @@ type Options struct {
 	NoAutoRotate   bool
 	NoProfile      bool
 	Interlace      bool
+	StripMetadata  bool
+	Trim           bool
 	Extend         Extend
 	Rotate         Angle
 	Background     Color
@@ -215,4 +217,5 @@ type Options struct {
 	Interpretation Interpretation
 	GaussianBlur   GaussianBlur
 	Sharpen        Sharpen
+	OutputICC      string
 }

+ 7 - 552
vendor/github.com/h2non/bimg/resize.go

@@ -1,561 +1,16 @@
-package bimg
+// +build go17
 
-/*
-#cgo pkg-config: vips
-#include "vips/vips.h"
-*/
-import "C"
+package bimg
 
 import (
-	"errors"
-	"math"
+	"runtime"
 )
 
 // Resize is used to transform a given image as byte buffer
 // with the passed options.
 func Resize(buf []byte, o Options) ([]byte, error) {
-	defer C.vips_thread_shutdown()
-
-	image, imageType, err := loadImage(buf)
-
-	if err != nil {
-		return nil, err
-	}
-
-	// Clone and define default options
-	o = applyDefaults(o, imageType)
-
-	if !IsTypeSupported(o.Type) {
-		return nil, errors.New("Unsupported image output type")
-	}
-
-	debug("Options: %#v", o)
-
-	// Auto rotate image based on EXIF orientation header
-	image, rotated, err := rotateAndFlipImage(image, o)
-	if err != nil {
-		return nil, err
-	}
-
-	// If JPEG image, retrieve the buffer
-	if rotated && imageType == JPEG && !o.NoAutoRotate {
-		buf, err = getImageBuffer(image)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	inWidth := int(image.Xsize)
-	inHeight := int(image.Ysize)
-
-	// Infer the required operation based on the in/out image sizes for a coherent transformation
-	normalizeOperation(&o, inWidth, inHeight)
-
-	// image calculations
-	factor := imageCalculations(&o, inWidth, inHeight)
-	shrink := calculateShrink(factor, o.Interpolator)
-	residual := calculateResidual(factor, shrink)
-
-	// Do not enlarge the output if the input width or height
-	// are already less than the required dimensions
-	if !o.Enlarge && !o.Force {
-		if inWidth < o.Width && inHeight < o.Height {
-			factor = 1.0
-			shrink = 1
-			residual = 0
-			o.Width = inWidth
-			o.Height = inHeight
-		}
-	}
-
-	// Try to use libjpeg shrink-on-load
-	if imageType == JPEG && shrink >= 2 {
-		tmpImage, factor, err := shrinkJpegImage(buf, image, factor, shrink)
-		if err != nil {
-			return nil, err
-		}
-
-		image = tmpImage
-		factor = math.Max(factor, 1.0)
-		shrink = int(math.Floor(factor))
-		residual = float64(shrink) / factor
-	}
-
-	// Zoom image, if necessary
-	image, err = zoomImage(image, o.Zoom)
-	if err != nil {
-		return nil, err
-	}
-
-	// Transform image, if necessary
-	if shouldTransformImage(o, inWidth, inHeight) {
-		image, err = transformImage(image, o, shrink, residual)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	// Apply effects, if necessary
-	if shouldApplyEffects(o) {
-		image, err = applyEffects(image, o)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	// Add watermark, if necessary
-	image, err = watermarkImageWithText(image, o.Watermark)
-	if err != nil {
-		return nil, err
-	}
-
-	// Add watermark, if necessary
-	image, err = watermarkImageWithAnotherImage(image, o.WatermarkImage)
-	if err != nil {
-		return nil, err
-	}
-
-	// Flatten image on a background, if necessary
-	image, err = imageFlatten(image, imageType, o)
-	if err != nil {
-		return nil, err
-	}
-
-	return saveImage(image, o)
-}
-
-func loadImage(buf []byte) (*C.VipsImage, ImageType, error) {
-	if len(buf) == 0 {
-		return nil, JPEG, errors.New("Image buffer is empty")
-	}
-
-	image, imageType, err := vipsRead(buf)
-	if err != nil {
-		return nil, JPEG, err
-	}
-
-	return image, imageType, nil
-}
-
-func applyDefaults(o Options, imageType ImageType) Options {
-	if o.Quality == 0 {
-		o.Quality = Quality
-	}
-	if o.Compression == 0 {
-		o.Compression = 6
-	}
-	if o.Type == 0 {
-		o.Type = imageType
-	}
-	if o.Interpretation == 0 {
-		o.Interpretation = InterpretationSRGB
-	}
-	return o
-}
-
-func saveImage(image *C.VipsImage, o Options) ([]byte, error) {
-	saveOptions := vipsSaveOptions{
-		Quality:        o.Quality,
-		Type:           o.Type,
-		Compression:    o.Compression,
-		Interlace:      o.Interlace,
-		NoProfile:      o.NoProfile,
-		Interpretation: o.Interpretation,
-	}
-	// Finally get the resultant buffer
-	return vipsSave(image, saveOptions)
-}
-
-func normalizeOperation(o *Options, inWidth, inHeight int) {
-	if !o.Force && !o.Crop && !o.Embed && !o.Enlarge && o.Rotate == 0 && (o.Width > 0 || o.Height > 0) {
-		o.Force = true
-	}
-}
-
-func shouldTransformImage(o Options, inWidth, inHeight int) bool {
-	return o.Force || (o.Width > 0 && o.Width != inWidth) ||
-		(o.Height > 0 && o.Height != inHeight) || o.AreaWidth > 0 || o.AreaHeight > 0
-}
-
-func shouldApplyEffects(o Options) bool {
-	return o.GaussianBlur.Sigma > 0 || o.GaussianBlur.MinAmpl > 0 || o.Sharpen.Radius > 0 && o.Sharpen.Y2 > 0 || o.Sharpen.Y3 > 0
-}
-
-func transformImage(image *C.VipsImage, o Options, shrink int, residual float64) (*C.VipsImage, error) {
-	var err error
-	// Use vips_shrink with the integral reduction
-	if shrink > 1 {
-		image, residual, err = shrinkImage(image, o, residual, shrink)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	residualx, residualy := residual, residual
-	if o.Force {
-		residualx = float64(o.Width) / float64(image.Xsize)
-		residualy = float64(o.Height) / float64(image.Ysize)
-	}
-
-	if o.Force || residual != 0 {
-		image, err = vipsAffine(image, residualx, residualy, o.Interpolator)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if o.Force {
-		o.Crop = false
-		o.Embed = false
-	}
-
-	image, err = extractOrEmbedImage(image, o)
-	if err != nil {
-		return nil, err
-	}
-
-	debug("Transform: shrink=%v, residual=%v, interpolator=%v",
-		shrink, residual, o.Interpolator.String())
-
-	return image, nil
-}
-
-func applyEffects(image *C.VipsImage, o Options) (*C.VipsImage, error) {
-	var err error
-
-	if o.GaussianBlur.Sigma > 0 || o.GaussianBlur.MinAmpl > 0 {
-		image, err = vipsGaussianBlur(image, o.GaussianBlur)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if o.Sharpen.Radius > 0 && o.Sharpen.Y2 > 0 || o.Sharpen.Y3 > 0 {
-		image, err = vipsSharpen(image, o.Sharpen)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	debug("Effects: gaussSigma=%v, gaussMinAmpl=%v, sharpenRadius=%v",
-		o.GaussianBlur.Sigma, o.GaussianBlur.MinAmpl, o.Sharpen.Radius)
-
-	return image, nil
-}
-
-func extractOrEmbedImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
-	var err error
-	inWidth := int(image.Xsize)
-	inHeight := int(image.Ysize)
-
-	switch {
-	case o.Gravity == GravitySmart, o.SmartCrop:
-		image, err = vipsSmartCrop(image, o.Width, o.Height)
-		break
-	case o.Crop:
-		width := int(math.Min(float64(inWidth), float64(o.Width)))
-		height := int(math.Min(float64(inHeight), float64(o.Height)))
-		left, top := calculateCrop(inWidth, inHeight, o.Width, o.Height, o.Gravity)
-		left, top = int(math.Max(float64(left), 0)), int(math.Max(float64(top), 0))
-		image, err = vipsExtract(image, left, top, width, height)
-		break
-	case o.Embed:
-		left, top := (o.Width-inWidth)/2, (o.Height-inHeight)/2
-		image, err = vipsEmbed(image, left, top, o.Width, o.Height, o.Extend, o.Background)
-		break
-
-	case o.Top != 0 || o.Left != 0 || o.AreaWidth != 0 || o.AreaHeight != 0:
-		if o.AreaWidth == 0 {
-			o.AreaHeight = o.Width
-		}
-		if o.AreaHeight == 0 {
-			o.AreaHeight = o.Height
-		}
-		if o.AreaWidth == 0 || o.AreaHeight == 0 {
-			return nil, errors.New("Extract area width/height params are required")
-		}
-		image, err = vipsExtract(image, o.Left, o.Top, o.AreaWidth, o.AreaHeight)
-		break
-	}
-
-	return image, err
-}
-
-func rotateAndFlipImage(image *C.VipsImage, o Options) (*C.VipsImage, bool, error) {
-	var err error
-	var rotated bool
-	var direction Direction = -1
-
-	if o.NoAutoRotate == false {
-		rotation, flip := calculateRotationAndFlip(image, o.Rotate)
-		if flip {
-			o.Flip = flip
-		}
-		if rotation > 0 && o.Rotate == 0 {
-			o.Rotate = rotation
-		}
-	}
-
-	if o.Rotate > 0 {
-		rotated = true
-		image, err = vipsRotate(image, getAngle(o.Rotate))
-	}
-
-	if o.Flip {
-		direction = Horizontal
-	} else if o.Flop {
-		direction = Vertical
-	}
-
-	if direction != -1 {
-		rotated = true
-		image, err = vipsFlip(image, direction)
-	}
-
-	return image, rotated, err
-}
-
-func watermarkImageWithText(image *C.VipsImage, w Watermark) (*C.VipsImage, error) {
-	if w.Text == "" {
-		return image, nil
-	}
-
-	// Defaults
-	if w.Font == "" {
-		w.Font = WatermarkFont
-	}
-	if w.Width == 0 {
-		w.Width = int(math.Floor(float64(image.Xsize / 6)))
-	}
-	if w.DPI == 0 {
-		w.DPI = 150
-	}
-	if w.Margin == 0 {
-		w.Margin = w.Width
-	}
-	if w.Opacity == 0 {
-		w.Opacity = 0.25
-	} else if w.Opacity > 1 {
-		w.Opacity = 1
-	}
-
-	image, err := vipsWatermark(image, w)
-	if err != nil {
-		return nil, err
-	}
-
-	return image, nil
-}
-
-func watermarkImageWithAnotherImage(image *C.VipsImage, w WatermarkImage) (*C.VipsImage, error) {
-
-	if len(w.Buf) == 0 {
-		return image, nil
-	}
-
-	if w.Opacity == 0.0 {
-		w.Opacity = 1.0
-	}
-
-	image, err := vipsDrawWatermark(image, w)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return image, nil
-}
-
-func imageFlatten(image *C.VipsImage, imageType ImageType, o Options) (*C.VipsImage, error) {
-	// Only PNG images are supported for now
-	if imageType != PNG || o.Background == ColorBlack {
-		return image, nil
-	}
-	return vipsFlattenBackground(image, o.Background)
-}
-
-func zoomImage(image *C.VipsImage, zoom int) (*C.VipsImage, error) {
-	if zoom == 0 {
-		return image, nil
-	}
-	return vipsZoom(image, zoom+1)
-}
-
-func shrinkImage(image *C.VipsImage, o Options, residual float64, shrink int) (*C.VipsImage, float64, error) {
-	// Use vips_shrink with the integral reduction
-	image, err := vipsShrink(image, shrink)
-	if err != nil {
-		return nil, 0, err
-	}
-
-	// Recalculate residual float based on dimensions of required vs shrunk images
-	residualx := float64(o.Width) / float64(image.Xsize)
-	residualy := float64(o.Height) / float64(image.Ysize)
-
-	if o.Crop {
-		residual = math.Max(residualx, residualy)
-	} else {
-		residual = math.Min(residualx, residualy)
-	}
-
-	return image, residual, nil
-}
-
-func shrinkJpegImage(buf []byte, input *C.VipsImage, factor float64, shrink int) (*C.VipsImage, float64, error) {
-	var image *C.VipsImage
-	var err error
-	shrinkOnLoad := 1
-
-	// Recalculate integral shrink and double residual
-	switch {
-	case shrink >= 8:
-		factor = factor / 8
-		shrinkOnLoad = 8
-	case shrink >= 4:
-		factor = factor / 4
-		shrinkOnLoad = 4
-	case shrink >= 2:
-		factor = factor / 2
-		shrinkOnLoad = 2
-	}
-
-	// Reload input using shrink-on-load
-	if shrinkOnLoad > 1 {
-		image, err = vipsShrinkJpeg(buf, input, shrinkOnLoad)
-	}
-
-	return image, factor, err
-}
-
-func imageCalculations(o *Options, inWidth, inHeight int) float64 {
-	factor := 1.0
-	xfactor := float64(inWidth) / float64(o.Width)
-	yfactor := float64(inHeight) / float64(o.Height)
-
-	switch {
-	// Fixed width and height
-	case o.Width > 0 && o.Height > 0:
-		if o.Crop {
-			factor = math.Min(xfactor, yfactor)
-		} else {
-			factor = math.Max(xfactor, yfactor)
-		}
-	// Fixed width, auto height
-	case o.Width > 0:
-		if o.Crop {
-			o.Height = inHeight
-		} else {
-			factor = xfactor
-			o.Height = roundFloat(float64(inHeight) / factor)
-		}
-	// Fixed height, auto width
-	case o.Height > 0:
-		if o.Crop {
-			o.Width = inWidth
-		} else {
-			factor = yfactor
-			o.Width = roundFloat(float64(inWidth) / factor)
-		}
-	// Identity transform
-	default:
-		o.Width = inWidth
-		o.Height = inHeight
-		break
-	}
-
-	return factor
-}
-
-func roundFloat(f float64) int {
-	if f < 0 {
-		return int(math.Ceil(f - 0.5))
-	}
-	return int(math.Floor(f + 0.5))
-}
-
-func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity) (int, int) {
-	left, top := 0, 0
-
-	switch gravity {
-	case GravityNorth:
-		left = (inWidth - outWidth + 1) / 2
-	case GravityEast:
-		left = inWidth - outWidth
-		top = (inHeight - outHeight + 1) / 2
-	case GravitySouth:
-		left = (inWidth - outWidth + 1) / 2
-		top = inHeight - outHeight
-	case GravityWest:
-		top = (inHeight - outHeight + 1) / 2
-	default:
-		left = (inWidth - outWidth + 1) / 2
-		top = (inHeight - outHeight + 1) / 2
-	}
-
-	return left, top
-}
-
-func calculateRotationAndFlip(image *C.VipsImage, angle Angle) (Angle, bool) {
-	rotate := D0
-	flip := false
-
-	if angle > 0 {
-		return rotate, flip
-	}
-
-	switch vipsExifOrientation(image) {
-	case 6:
-		rotate = D90
-		break
-	case 3:
-		rotate = D180
-		break
-	case 8:
-		rotate = D270
-		break
-	case 2:
-		flip = true
-		break // flip 1
-	case 7:
-		flip = true
-		rotate = D90
-		break // flip 6
-	case 4:
-		flip = true
-		rotate = D180
-		break // flip 3
-	case 5:
-		flip = true
-		rotate = D270
-		break // flip 8
-	}
-
-	return rotate, flip
-}
-
-func calculateShrink(factor float64, i Interpolator) int {
-	var shrink float64
-
-	// Calculate integral box shrink
-	windowSize := vipsWindowSize(i.String())
-	if factor >= 2 && windowSize > 3 {
-		// Shrink less, affine more with interpolators that use at least 4x4 pixel window, e.g. bicubic
-		shrink = float64(math.Floor(factor * 3.0 / windowSize))
-	} else {
-		shrink = math.Floor(factor)
-	}
-
-	return int(math.Max(shrink, 1))
-}
-
-func calculateResidual(factor float64, shrink int) float64 {
-	return float64(shrink) / factor
-}
-
-func getAngle(angle Angle) Angle {
-	divisor := angle % 90
-	if divisor != 0 {
-		angle = angle - divisor
-	}
-	return Angle(math.Min(float64(angle), 270))
+	// Required in order to prevent premature garbage collection. See:
+	// https://github.com/h2non/bimg/pull/162
+	defer runtime.KeepAlive(buf)
+	return resizer(buf, o)
 }

+ 10 - 0
vendor/github.com/h2non/bimg/resize_legacy.go

@@ -0,0 +1,10 @@
+// +build !go17
+
+package bimg
+
+// Resize is used to transform a given image as byte buffer
+// with the passed options.
+// Used as proxy to resizer() only in Go <= 1.6 versions
+func Resize(buf []byte, o Options) ([]byte, error) {
+	return resizer(buf, o)
+}

+ 572 - 0
vendor/github.com/h2non/bimg/resizer.go

@@ -0,0 +1,572 @@
+package bimg
+
+/*
+#cgo pkg-config: vips
+#include "vips/vips.h"
+*/
+import "C"
+
+import (
+	"errors"
+	"math"
+)
+
+// resizer is used to transform a given image as byte buffer
+// with the passed options.
+func resizer(buf []byte, o Options) ([]byte, error) {
+	defer C.vips_thread_shutdown()
+
+	image, imageType, err := loadImage(buf)
+	if err != nil {
+		return nil, err
+	}
+
+	// Clone and define default options
+	o = applyDefaults(o, imageType)
+
+	if !IsTypeSupported(o.Type) {
+		return nil, errors.New("Unsupported image output type")
+	}
+
+	debug("Options: %#v", o)
+
+	// Auto rotate image based on EXIF orientation header
+	image, rotated, err := rotateAndFlipImage(image, o)
+	if err != nil {
+		return nil, err
+	}
+
+	// If JPEG image, retrieve the buffer
+	if rotated && imageType == JPEG && !o.NoAutoRotate {
+		buf, err = getImageBuffer(image)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	inWidth := int(image.Xsize)
+	inHeight := int(image.Ysize)
+
+	// Infer the required operation based on the in/out image sizes for a coherent transformation
+	normalizeOperation(&o, inWidth, inHeight)
+
+	// image calculations
+	factor := imageCalculations(&o, inWidth, inHeight)
+	shrink := calculateShrink(factor, o.Interpolator)
+	residual := calculateResidual(factor, shrink)
+
+	// Do not enlarge the output if the input width or height
+	// are already less than the required dimensions
+	if !o.Enlarge && !o.Force {
+		if inWidth < o.Width && inHeight < o.Height {
+			factor = 1.0
+			shrink = 1
+			residual = 0
+			o.Width = inWidth
+			o.Height = inHeight
+		}
+	}
+
+	// Try to use libjpeg shrink-on-load
+	if imageType == JPEG && shrink >= 2 {
+		tmpImage, factor, err := shrinkJpegImage(buf, image, factor, shrink)
+		if err != nil {
+			return nil, err
+		}
+
+		image = tmpImage
+		factor = math.Max(factor, 1.0)
+		shrink = int(math.Floor(factor))
+		residual = float64(shrink) / factor
+	}
+
+	// Zoom image, if necessary
+	image, err = zoomImage(image, o.Zoom)
+	if err != nil {
+		return nil, err
+	}
+
+	// Transform image, if necessary
+	if shouldTransformImage(o, inWidth, inHeight) {
+		image, err = transformImage(image, o, shrink, residual)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Apply effects, if necessary
+	if shouldApplyEffects(o) {
+		image, err = applyEffects(image, o)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Add watermark, if necessary
+	image, err = watermarkImageWithText(image, o.Watermark)
+	if err != nil {
+		return nil, err
+	}
+
+	// Add watermark, if necessary
+	image, err = watermarkImageWithAnotherImage(image, o.WatermarkImage)
+	if err != nil {
+		return nil, err
+	}
+
+	// Flatten image on a background, if necessary
+	image, err = imageFlatten(image, imageType, o)
+	if err != nil {
+		return nil, err
+	}
+
+	return saveImage(image, o)
+}
+
+func loadImage(buf []byte) (*C.VipsImage, ImageType, error) {
+	if len(buf) == 0 {
+		return nil, JPEG, errors.New("Image buffer is empty")
+	}
+
+	image, imageType, err := vipsRead(buf)
+	if err != nil {
+		return nil, JPEG, err
+	}
+
+	return image, imageType, nil
+}
+
+func applyDefaults(o Options, imageType ImageType) Options {
+	if o.Quality == 0 {
+		o.Quality = Quality
+	}
+	if o.Compression == 0 {
+		o.Compression = 6
+	}
+	if o.Type == 0 {
+		o.Type = imageType
+	}
+	if o.Interpretation == 0 {
+		o.Interpretation = InterpretationSRGB
+	}
+	return o
+}
+
+func saveImage(image *C.VipsImage, o Options) ([]byte, error) {
+	saveOptions := vipsSaveOptions{
+		Quality:        o.Quality,
+		Type:           o.Type,
+		Compression:    o.Compression,
+		Interlace:      o.Interlace,
+		NoProfile:      o.NoProfile,
+		Interpretation: o.Interpretation,
+		OutputICC:      o.OutputICC,
+		StripMetadata:  o.StripMetadata,
+	}
+	// Finally get the resultant buffer
+	return vipsSave(image, saveOptions)
+}
+
+func normalizeOperation(o *Options, inWidth, inHeight int) {
+	if !o.Force && !o.Crop && !o.Embed && !o.Enlarge && o.Rotate == 0 && (o.Width > 0 || o.Height > 0) {
+		o.Force = true
+	}
+}
+
+func shouldTransformImage(o Options, inWidth, inHeight int) bool {
+	return o.Force || (o.Width > 0 && o.Width != inWidth) ||
+		(o.Height > 0 && o.Height != inHeight) || o.AreaWidth > 0 || o.AreaHeight > 0 ||
+		o.Trim
+}
+
+func shouldApplyEffects(o Options) bool {
+	return o.GaussianBlur.Sigma > 0 || o.GaussianBlur.MinAmpl > 0 || o.Sharpen.Radius > 0 && o.Sharpen.Y2 > 0 || o.Sharpen.Y3 > 0
+}
+
+func transformImage(image *C.VipsImage, o Options, shrink int, residual float64) (*C.VipsImage, error) {
+	var err error
+	// Use vips_shrink with the integral reduction
+	if shrink > 1 {
+		image, residual, err = shrinkImage(image, o, residual, shrink)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	residualx, residualy := residual, residual
+	if o.Force {
+		residualx = float64(o.Width) / float64(image.Xsize)
+		residualy = float64(o.Height) / float64(image.Ysize)
+	}
+
+	if o.Force || residual != 0 {
+		if residualx < 1 && residualy < 1 {
+			image, err = vipsReduce(image, 1/residualx, 1/residualy)
+		} else {
+			image, err = vipsAffine(image, residualx, residualy, o.Interpolator)
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if o.Force {
+		o.Crop = false
+		o.Embed = false
+	}
+
+	image, err = extractOrEmbedImage(image, o)
+	if err != nil {
+		return nil, err
+	}
+
+	debug("Transform: shrink=%v, residual=%v, interpolator=%v",
+		shrink, residual, o.Interpolator.String())
+
+	return image, nil
+}
+
+func applyEffects(image *C.VipsImage, o Options) (*C.VipsImage, error) {
+	var err error
+
+	if o.GaussianBlur.Sigma > 0 || o.GaussianBlur.MinAmpl > 0 {
+		image, err = vipsGaussianBlur(image, o.GaussianBlur)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if o.Sharpen.Radius > 0 && o.Sharpen.Y2 > 0 || o.Sharpen.Y3 > 0 {
+		image, err = vipsSharpen(image, o.Sharpen)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	debug("Effects: gaussSigma=%v, gaussMinAmpl=%v, sharpenRadius=%v",
+		o.GaussianBlur.Sigma, o.GaussianBlur.MinAmpl, o.Sharpen.Radius)
+
+	return image, nil
+}
+
+func extractOrEmbedImage(image *C.VipsImage, o Options) (*C.VipsImage, error) {
+	var err error
+	inWidth := int(image.Xsize)
+	inHeight := int(image.Ysize)
+
+	switch {
+	case o.Gravity == GravitySmart, o.SmartCrop:
+		image, err = vipsSmartCrop(image, o.Width, o.Height)
+		break
+	case o.Crop:
+		width := int(math.Min(float64(inWidth), float64(o.Width)))
+		height := int(math.Min(float64(inHeight), float64(o.Height)))
+		left, top := calculateCrop(inWidth, inHeight, o.Width, o.Height, o.Gravity)
+		left, top = int(math.Max(float64(left), 0)), int(math.Max(float64(top), 0))
+		image, err = vipsExtract(image, left, top, width, height)
+		break
+	case o.Embed:
+		left, top := (o.Width-inWidth)/2, (o.Height-inHeight)/2
+		image, err = vipsEmbed(image, left, top, o.Width, o.Height, o.Extend, o.Background)
+		break
+	case o.Trim:
+		left, top, width, height, err := vipsTrim(image)
+		if err == nil {
+			image, err = vipsExtract(image, left, top, width, height)
+		}
+		break
+	case o.Top != 0 || o.Left != 0 || o.AreaWidth != 0 || o.AreaHeight != 0:
+		if o.AreaWidth == 0 {
+			o.AreaHeight = o.Width
+		}
+		if o.AreaHeight == 0 {
+			o.AreaHeight = o.Height
+		}
+		if o.AreaWidth == 0 || o.AreaHeight == 0 {
+			return nil, errors.New("Extract area width/height params are required")
+		}
+		image, err = vipsExtract(image, o.Left, o.Top, o.AreaWidth, o.AreaHeight)
+		break
+	}
+
+	return image, err
+}
+
+func rotateAndFlipImage(image *C.VipsImage, o Options) (*C.VipsImage, bool, error) {
+	var err error
+	var rotated bool
+	var direction Direction = -1
+
+	if o.NoAutoRotate == false {
+		rotation, flip := calculateRotationAndFlip(image, o.Rotate)
+		if flip {
+			o.Flip = flip
+		}
+		if rotation > 0 && o.Rotate == 0 {
+			o.Rotate = rotation
+		}
+	}
+
+	if o.Rotate > 0 {
+		rotated = true
+		image, err = vipsRotate(image, getAngle(o.Rotate))
+	}
+
+	if o.Flip {
+		direction = Horizontal
+	} else if o.Flop {
+		direction = Vertical
+	}
+
+	if direction != -1 {
+		rotated = true
+		image, err = vipsFlip(image, direction)
+	}
+
+	return image, rotated, err
+}
+
+func watermarkImageWithText(image *C.VipsImage, w Watermark) (*C.VipsImage, error) {
+	if w.Text == "" {
+		return image, nil
+	}
+
+	// Defaults
+	if w.Font == "" {
+		w.Font = WatermarkFont
+	}
+	if w.Width == 0 {
+		w.Width = int(math.Floor(float64(image.Xsize / 6)))
+	}
+	if w.DPI == 0 {
+		w.DPI = 150
+	}
+	if w.Margin == 0 {
+		w.Margin = w.Width
+	}
+	if w.Opacity == 0 {
+		w.Opacity = 0.25
+	} else if w.Opacity > 1 {
+		w.Opacity = 1
+	}
+
+	image, err := vipsWatermark(image, w)
+	if err != nil {
+		return nil, err
+	}
+
+	return image, nil
+}
+
+func watermarkImageWithAnotherImage(image *C.VipsImage, w WatermarkImage) (*C.VipsImage, error) {
+
+	if len(w.Buf) == 0 {
+		return image, nil
+	}
+
+	if w.Opacity == 0.0 {
+		w.Opacity = 1.0
+	}
+
+	image, err := vipsDrawWatermark(image, w)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return image, nil
+}
+
+func imageFlatten(image *C.VipsImage, imageType ImageType, o Options) (*C.VipsImage, error) {
+	// Only PNG images are supported for now
+	if imageType != PNG || o.Background == ColorBlack {
+		return image, nil
+	}
+	return vipsFlattenBackground(image, o.Background)
+}
+
+func zoomImage(image *C.VipsImage, zoom int) (*C.VipsImage, error) {
+	if zoom == 0 {
+		return image, nil
+	}
+	return vipsZoom(image, zoom+1)
+}
+
+func shrinkImage(image *C.VipsImage, o Options, residual float64, shrink int) (*C.VipsImage, float64, error) {
+	// Use vips_shrink with the integral reduction
+	image, err := vipsShrink(image, shrink)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	// Recalculate residual float based on dimensions of required vs shrunk images
+	residualx := float64(o.Width) / float64(image.Xsize)
+	residualy := float64(o.Height) / float64(image.Ysize)
+
+	if o.Crop {
+		residual = math.Max(residualx, residualy)
+	} else {
+		residual = math.Min(residualx, residualy)
+	}
+
+	return image, residual, nil
+}
+
+func shrinkJpegImage(buf []byte, input *C.VipsImage, factor float64, shrink int) (*C.VipsImage, float64, error) {
+	var image *C.VipsImage
+	var err error
+	shrinkOnLoad := 1
+
+	// Recalculate integral shrink and double residual
+	switch {
+	case shrink >= 8:
+		factor = factor / 8
+		shrinkOnLoad = 8
+	case shrink >= 4:
+		factor = factor / 4
+		shrinkOnLoad = 4
+	case shrink >= 2:
+		factor = factor / 2
+		shrinkOnLoad = 2
+	}
+
+	// Reload input using shrink-on-load
+	if shrinkOnLoad > 1 {
+		image, err = vipsShrinkJpeg(buf, input, shrinkOnLoad)
+	}
+
+	return image, factor, err
+}
+
+func imageCalculations(o *Options, inWidth, inHeight int) float64 {
+	factor := 1.0
+	xfactor := float64(inWidth) / float64(o.Width)
+	yfactor := float64(inHeight) / float64(o.Height)
+
+	switch {
+	// Fixed width and height
+	case o.Width > 0 && o.Height > 0:
+		if o.Crop {
+			factor = math.Min(xfactor, yfactor)
+		} else {
+			factor = math.Max(xfactor, yfactor)
+		}
+	// Fixed width, auto height
+	case o.Width > 0:
+		if o.Crop {
+			o.Height = inHeight
+		} else {
+			factor = xfactor
+			o.Height = roundFloat(float64(inHeight) / factor)
+		}
+	// Fixed height, auto width
+	case o.Height > 0:
+		if o.Crop {
+			o.Width = inWidth
+		} else {
+			factor = yfactor
+			o.Width = roundFloat(float64(inWidth) / factor)
+		}
+	// Identity transform
+	default:
+		o.Width = inWidth
+		o.Height = inHeight
+		break
+	}
+
+	return factor
+}
+
+func roundFloat(f float64) int {
+	if f < 0 {
+		return int(math.Ceil(f - 0.5))
+	}
+	return int(math.Floor(f + 0.5))
+}
+
+func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity) (int, int) {
+	left, top := 0, 0
+
+	switch gravity {
+	case GravityNorth:
+		left = (inWidth - outWidth + 1) / 2
+	case GravityEast:
+		left = inWidth - outWidth
+		top = (inHeight - outHeight + 1) / 2
+	case GravitySouth:
+		left = (inWidth - outWidth + 1) / 2
+		top = inHeight - outHeight
+	case GravityWest:
+		top = (inHeight - outHeight + 1) / 2
+	default:
+		left = (inWidth - outWidth + 1) / 2
+		top = (inHeight - outHeight + 1) / 2
+	}
+
+	return left, top
+}
+
+func calculateRotationAndFlip(image *C.VipsImage, angle Angle) (Angle, bool) {
+	rotate := D0
+	flip := false
+
+	if angle > 0 {
+		return rotate, flip
+	}
+
+	switch vipsExifOrientation(image) {
+	case 6:
+		rotate = D90
+		break
+	case 3:
+		rotate = D180
+		break
+	case 8:
+		rotate = D270
+		break
+	case 2:
+		flip = true
+		break // flip 1
+	case 7:
+		flip = true
+		rotate = D270
+		break // flip 6
+	case 4:
+		flip = true
+		rotate = D180
+		break // flip 3
+	case 5:
+		flip = true
+		rotate = D90
+		break // flip 8
+	}
+
+	return rotate, flip
+}
+
+func calculateShrink(factor float64, i Interpolator) int {
+	var shrink float64
+
+	// Calculate integral box shrink
+	windowSize := vipsWindowSize(i.String())
+	if factor >= 2 && windowSize > 3 {
+		// Shrink less, affine more with interpolators that use at least 4x4 pixel window, e.g. bicubic
+		shrink = float64(math.Floor(factor * 3.0 / windowSize))
+	} else {
+		shrink = math.Floor(factor)
+	}
+
+	return int(math.Max(shrink, 1))
+}
+
+func calculateResidual(factor float64, shrink int) float64 {
+	return float64(shrink) / factor
+}
+
+func getAngle(angle Angle) Angle {
+	divisor := angle % 90
+	if divisor != 0 {
+		angle = angle - divisor
+	}
+	return Angle(math.Min(float64(angle), 270))
+}

+ 60 - 0
vendor/github.com/h2non/bimg/resize_test.go → vendor/github.com/h2non/bimg/resizer_test.go

@@ -3,6 +3,7 @@ package bimg
 import (
 	"bytes"
 	"crypto/md5"
+	"fmt"
 	"image"
 	"image/jpeg"
 	"io/ioutil"
@@ -393,6 +394,65 @@ func TestResizePngWithTransparency(t *testing.T) {
 	Write("fixtures/transparent_out.png", newImg)
 }
 
+func TestRotationAndFlip(t *testing.T) {
+	files := []struct {
+		Name  string
+		Angle Angle
+		Flip  bool
+	}{
+		{"Landscape_1", 0, false},
+		{"Landscape_2", 0, true},
+		{"Landscape_3", D180, false},
+		{"Landscape_4", D180, true},
+		{"Landscape_5", D90, true},
+		{"Landscape_6", D90, false},
+		{"Landscape_7", D270, true},
+		{"Landscape_8", D270, false},
+		{"Portrait_1", 0, false},
+		{"Portrait_2", 0, true},
+		{"Portrait_3", D180, false},
+		{"Portrait_4", D180, true},
+		{"Portrait_5", D90, true},
+		{"Portrait_6", D90, false},
+		{"Portrait_7", D270, true},
+		{"Portrait_8", D270, false},
+	}
+
+	for _, file := range files {
+		img, err := os.Open(fmt.Sprintf("fixtures/exif/%s.jpg", file.Name))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		buf, err := ioutil.ReadAll(img)
+		if err != nil {
+			t.Fatal(err)
+		}
+		img.Close()
+
+		image, _, err := loadImage(buf)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		angle, flip := calculateRotationAndFlip(image, D0)
+		if angle != file.Angle {
+			t.Errorf("Rotation for %v expected to be %v. got %v", file.Name, file.Angle, angle)
+		}
+		if flip != file.Flip {
+			t.Errorf("Flip for %v expected to be %v. got %v", file.Name, file.Flip, flip)
+		}
+
+		// Visual debugging.
+		newImg, err := Resize(buf, Options{})
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		Write(fmt.Sprintf("fixtures/exif/%s_out.jpg", file.Name), newImg)
+	}
+}
+
 func TestIfBothSmartCropOptionsAreIdentical(t *testing.T) {
 	if !(VipsMajorVersion >= 8 && VipsMinorVersion > 4) {
 		t.Skipf("Skipping this test, libvips doesn't meet version requirement %s > 8.4", VipsVersion)

+ 5 - 3
vendor/github.com/h2non/bimg/type_test.go

@@ -26,8 +26,10 @@ func TestDeterminateImageType(t *testing.T) {
 		buf, _ := ioutil.ReadAll(img)
 		defer img.Close()
 
-		if DetermineImageType(buf) != file.expected {
-			t.Fatal("Image type is not valid")
+		if VipsIsTypeSupported(file.expected) {
+			if DetermineImageType(buf) != file.expected {
+				t.Fatalf("Image type is not valid: %s != %s", file.name, ImageTypes[file.expected])
+			}
 		}
 	}
 }
@@ -52,7 +54,7 @@ func TestDeterminateImageTypeName(t *testing.T) {
 		defer img.Close()
 
 		if DetermineImageTypeName(buf) != file.expected {
-			t.Fatal("Image type is not valid")
+			t.Fatalf("Image type is not valid: %s != %s", file.name, file.expected)
 		}
 	}
 }

+ 1 - 1
vendor/github.com/h2non/bimg/version.go

@@ -1,4 +1,4 @@
 package bimg
 
 // Version represents the current package semantic version.
-const Version = "1.0.10"
+const Version = "1.0.14"

+ 57 - 13
vendor/github.com/h2non/bimg/vips.go

@@ -55,6 +55,8 @@ type vipsSaveOptions struct {
 	Type           ImageType
 	Interlace      bool
 	NoProfile      bool
+	StripMetadata  bool
+	OutputICC      string // Absolute path to the output ICC profile
 	Interpretation Interpretation
 }
 
@@ -362,6 +364,7 @@ func vipsFlattenBackground(image *C.VipsImage, background Color) (*C.VipsImage,
 }
 
 func vipsPreSave(image *C.VipsImage, o *vipsSaveOptions) (*C.VipsImage, error) {
+	var outImage *C.VipsImage
 	// Remove ICC profile metadata
 	if o.NoProfile {
 		C.remove_profile(image)
@@ -374,7 +377,6 @@ func vipsPreSave(image *C.VipsImage, o *vipsSaveOptions) (*C.VipsImage, error) {
 	interpretation := C.VipsInterpretation(o.Interpretation)
 
 	// Apply the proper colour space
-	var outImage *C.VipsImage
 	if vipsColourspaceIsSupported(image) {
 		err := C.vips_colourspace_bridge(image, &outImage, interpretation)
 		if int(err) != 0 {
@@ -383,6 +385,18 @@ func vipsPreSave(image *C.VipsImage, o *vipsSaveOptions) (*C.VipsImage, error) {
 		image = outImage
 	}
 
+	if o.OutputICC != "" && vipsHasProfile(image) {
+		debug("Embedded ICC profile found, trying to convert to %s", o.OutputICC)
+		outputIccPath := C.CString(o.OutputICC)
+		defer C.free(unsafe.Pointer(outputIccPath))
+
+		err := C.vips_icc_transform_bridge(image, &outImage, outputIccPath)
+		if int(err) != 0 {
+			return nil, catchVipsError()
+		}
+		image = outImage
+	}
+
 	return image, nil
 }
 
@@ -407,6 +421,7 @@ func vipsSave(image *C.VipsImage, o vipsSaveOptions) ([]byte, error) {
 	saveErr := C.int(0)
 	interlace := C.int(boolToInt(o.Interlace))
 	quality := C.int(o.Quality)
+	strip := C.int(boolToInt(o.StripMetadata))
 
 	if o.Type != 0 && !IsTypeSupportedSave(o.Type) {
 		return nil, fmt.Errorf("VIPS cannot save to %#v", ImageTypes[o.Type])
@@ -414,13 +429,13 @@ func vipsSave(image *C.VipsImage, o vipsSaveOptions) ([]byte, error) {
 	var ptr unsafe.Pointer
 	switch o.Type {
 	case WEBP:
-		saveErr = C.vips_webpsave_bridge(tmpImage, &ptr, &length, 1, quality)
+		saveErr = C.vips_webpsave_bridge(tmpImage, &ptr, &length, strip, quality)
 	case PNG:
-		saveErr = C.vips_pngsave_bridge(tmpImage, &ptr, &length, 1, C.int(o.Compression), quality, interlace)
+		saveErr = C.vips_pngsave_bridge(tmpImage, &ptr, &length, strip, C.int(o.Compression), quality, interlace)
 	case TIFF:
 		saveErr = C.vips_tiffsave_bridge(tmpImage, &ptr, &length)
 	default:
-		saveErr = C.vips_jpegsave_bridge(tmpImage, &ptr, &length, 1, quality, interlace)
+		saveErr = C.vips_jpegsave_bridge(tmpImage, &ptr, &length, strip, quality, interlace)
 	}
 
 	if int(saveErr) != 0 {
@@ -488,6 +503,22 @@ func vipsSmartCrop(image *C.VipsImage, width, height int) (*C.VipsImage, error)
 	return buf, nil
 }
 
+func vipsTrim(image *C.VipsImage) (int, int, int, int, error) {
+	defer C.g_object_unref(C.gpointer(image))
+
+	top := C.int(0)
+	left := C.int(0)
+	width := C.int(0)
+	height := C.int(0)
+
+	err := C.vips_find_trim_bridge(image, &top, &left, &width, &height)
+	if err != 0 {
+		return 0, 0, 0, 0, catchVipsError()
+	}
+
+	return int(top), int(left), int(width), int(height), nil
+}
+
 func vipsShrinkJpeg(buf []byte, input *C.VipsImage, shrink int) (*C.VipsImage, error) {
 	var image *C.VipsImage
 	var ptr = unsafe.Pointer(&buf[0])
@@ -513,6 +544,18 @@ func vipsShrink(input *C.VipsImage, shrink int) (*C.VipsImage, error) {
 	return image, nil
 }
 
+func vipsReduce(input *C.VipsImage, xshrink float64, yshrink float64) (*C.VipsImage, error) {
+	var image *C.VipsImage
+	defer C.g_object_unref(C.gpointer(input))
+
+	err := C.vips_reduce_bridge(input, &image, C.double(xshrink), C.double(yshrink))
+	if err != 0 {
+		return nil, catchVipsError()
+	}
+
+	return image, nil
+}
+
 func vipsEmbed(input *C.VipsImage, left, top, width, height int, extend Extend, background Color) (*C.VipsImage, error) {
 	var image *C.VipsImage
 
@@ -549,35 +592,36 @@ func vipsAffine(input *C.VipsImage, residualx, residualy float64, i Interpolator
 }
 
 func vipsImageType(buf []byte) ImageType {
-	if len(buf) == 0 {
+	if len(buf) < 12 {
 		return UNKNOWN
 	}
-	if buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47 {
-		return PNG
-	}
 	if buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF {
 		return JPEG
 	}
-	if IsTypeSupported(WEBP) && buf[8] == 0x57 && buf[9] == 0x45 && buf[10] == 0x42 && buf[11] == 0x50 {
-		return WEBP
+	if IsTypeSupported(GIF) && buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46 {
+		return GIF
+	}
+	if buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47 {
+		return PNG
 	}
 	if IsTypeSupported(TIFF) &&
 		((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) ||
 			(buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A)) {
 		return TIFF
 	}
-	if IsTypeSupported(GIF) && buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46 {
-		return GIF
-	}
 	if IsTypeSupported(PDF) && buf[0] == 0x25 && buf[1] == 0x50 && buf[2] == 0x44 && buf[3] == 0x46 {
 		return PDF
 	}
+	if IsTypeSupported(WEBP) && buf[8] == 0x57 && buf[9] == 0x45 && buf[10] == 0x42 && buf[11] == 0x50 {
+		return WEBP
+	}
 	if IsTypeSupported(SVG) && IsSVGImage(buf) {
 		return SVG
 	}
 	if IsTypeSupported(MAGICK) && strings.HasSuffix(readImageType(buf), "MagickBuffer") {
 		return MAGICK
 	}
+
 	return UNKNOWN
 }
 

+ 29 - 12
vendor/github.com/h2non/bimg/vips.h

@@ -20,6 +20,9 @@
 
 #define EXIF_IFD0_ORIENTATION "exif-ifd0-Orientation"
 
+#define INT_TO_GBOOLEAN(bool) (bool > 0 ? TRUE : FALSE)
+
+
 enum types {
 	UNKNOWN = 0,
 	JPEG,
@@ -62,11 +65,6 @@ remove_profile(VipsImage *image) {
 	vips_image_remove(image, VIPS_META_ICC_NAME);
 }
 
-static gboolean
-with_interlace(int interlace) {
-	return interlace > 0 ? TRUE : FALSE;
-}
-
 static int
 has_alpha_channel(VipsImage *image) {
 	return (
@@ -122,6 +120,11 @@ vips_shrink_bridge(VipsImage *in, VipsImage **out, double xshrink, double yshrin
 	return vips_shrink(in, out, xshrink, yshrink, NULL);
 }
 
+int
+vips_reduce_bridge(VipsImage *in, VipsImage **out, double xshrink, double yshrink) {
+	return vips_reduce(in, out, xshrink, yshrink, NULL);
+}
+
 int
 vips_type_find_bridge(int t) {
 	if (t == GIF) {
@@ -260,13 +263,19 @@ vips_colourspace_bridge(VipsImage *in, VipsImage **out, VipsInterpretation space
 	return vips_colourspace(in, out, space, NULL);
 }
 
+int
+vips_icc_transform_bridge (VipsImage *in, VipsImage **out, const char *output_icc_profile) {
+	// `output_icc_profile` represents the absolute path to the output ICC profile file
+	return vips_icc_transform(in, out, output_icc_profile, "embedded", TRUE, NULL);
+}
+
 int
 vips_jpegsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality, int interlace) {
 	return vips_jpegsave_buffer(in, buf, len,
-		"strip", strip,
+		"strip", INT_TO_GBOOLEAN(strip),
 		"Q", quality,
 		"optimize_coding", TRUE,
-		"interlace", with_interlace(interlace),
+		"interlace", INT_TO_GBOOLEAN(interlace),
 		NULL
 	);
 }
@@ -275,17 +284,17 @@ int
 vips_pngsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int compression, int quality, int interlace) {
 #if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42))
 	return vips_pngsave_buffer(in, buf, len,
-		"strip", FALSE,
+		"strip", INT_TO_GBOOLEAN(strip),
 		"compression", compression,
-		"interlace", with_interlace(interlace),
+		"interlace", INT_TO_GBOOLEAN(interlace),
 		"filter", VIPS_FOREIGN_PNG_FILTER_NONE,
 		NULL
 	);
 #else
 	return vips_pngsave_buffer(in, buf, len,
-		"strip", FALSE,
+		"strip", INT_TO_GBOOLEAN(strip),
 		"compression", compression,
-		"interlace", with_interlace(interlace),
+		"interlace", INT_TO_GBOOLEAN(interlace),
 		NULL
 	);
 #endif
@@ -294,7 +303,7 @@ vips_pngsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int compr
 int
 vips_webpsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality) {
 	return vips_webpsave_buffer(in, buf, len,
-		"strip", strip,
+		"strip", INT_TO_GBOOLEAN(strip),
 		"Q", quality,
 		NULL
 	);
@@ -530,3 +539,11 @@ vips_smartcrop_bridge(VipsImage *in, VipsImage **out, int width, int height) {
 	return 0;
 #endif
 }
+
+int vips_find_trim_bridge(VipsImage *in, int *top, int *left, int *width, int *height) {
+#if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 6)
+	return vips_find_trim(in, top, left, width, height, NULL);
+#else
+	return 0;
+#endif
+}

+ 8 - 1
vendor/github.com/h2non/bimg/vips_test.go

@@ -33,7 +33,7 @@ func TestVipsSave(t *testing.T) {
 
 	for _, typ := range types {
 		image, _, _ := vipsRead(readImage("test.jpg"))
-		options := vipsSaveOptions{Quality: 95, Type: typ}
+		options := vipsSaveOptions{Quality: 95, Type: typ, StripMetadata: true}
 
 		buf, err := vipsSave(image, options)
 		if err != nil {
@@ -144,6 +144,13 @@ func TestVipsImageType(t *testing.T) {
 	}
 }
 
+func TestVipsImageTypeInvalid(t *testing.T) {
+	imgType := vipsImageType([]byte("vip"))
+	if imgType != UNKNOWN {
+		t.Fatal("Invalid image type")
+	}
+}
+
 func TestVipsMemory(t *testing.T) {
 	mem := VipsMemory()
 

+ 27 - 15
vendor/golang.org/x/image/vector/raster_floating.go

@@ -54,13 +54,25 @@ func (z *Rasterizer) floatingLineTo(bx, by float32) {
 
 	for ; y < yMax; y++ {
 		dy := floatingMin(float32(y+1), by) - floatingMax(float32(y), ay)
-		xNext := x + dy*dxdy
+
+		// The "float32" in expressions like "float32(foo*bar)" here and below
+		// look redundant, since foo and bar already have type float32, but are
+		// explicit in order to disable the compiler's Fused Multiply Add (FMA)
+		// instruction selection, which can improve performance but can result
+		// in different rounding errors in floating point computations.
+		//
+		// This package aims to have bit-exact identical results across all
+		// GOARCHes, and across pure Go code and assembly, so it disables FMA.
+		//
+		// See the discussion at
+		// https://groups.google.com/d/topic/golang-dev/Sti0bl2xUXQ/discussion
+		xNext := x + float32(dy*dxdy)
 		if y < 0 {
 			x = xNext
 			continue
 		}
 		buf := z.bufF32[y*width:]
-		d := dy * dir
+		d := float32(dy * dir)
 		x0, x1 := x, xNext
 		if x > xNext {
 			x0, x1 = x1, x0
@@ -71,48 +83,48 @@ func (z *Rasterizer) floatingLineTo(bx, by float32) {
 		x1Ceil := float32(x1i)
 
 		if x1i <= x0i+1 {
-			xmf := 0.5*(x+xNext) - x0Floor
+			xmf := float32(0.5*(x+xNext)) - x0Floor
 			if i := clamp(x0i+0, width); i < uint(len(buf)) {
-				buf[i] += d - d*xmf
+				buf[i] += d - float32(d*xmf)
 			}
 			if i := clamp(x0i+1, width); i < uint(len(buf)) {
-				buf[i] += d * xmf
+				buf[i] += float32(d * xmf)
 			}
 		} else {
 			s := 1 / (x1 - x0)
 			x0f := x0 - x0Floor
 			oneMinusX0f := 1 - x0f
-			a0 := 0.5 * s * oneMinusX0f * oneMinusX0f
+			a0 := float32(0.5 * s * oneMinusX0f * oneMinusX0f)
 			x1f := x1 - x1Ceil + 1
-			am := 0.5 * s * x1f * x1f
+			am := float32(0.5 * s * x1f * x1f)
 
 			if i := clamp(x0i, width); i < uint(len(buf)) {
-				buf[i] += d * a0
+				buf[i] += float32(d * a0)
 			}
 
 			if x1i == x0i+2 {
 				if i := clamp(x0i+1, width); i < uint(len(buf)) {
-					buf[i] += d * (1 - a0 - am)
+					buf[i] += float32(d * (1 - a0 - am))
 				}
 			} else {
-				a1 := s * (1.5 - x0f)
+				a1 := float32(s * (1.5 - x0f))
 				if i := clamp(x0i+1, width); i < uint(len(buf)) {
-					buf[i] += d * (a1 - a0)
+					buf[i] += float32(d * (a1 - a0))
 				}
-				dTimesS := d * s
+				dTimesS := float32(d * s)
 				for xi := x0i + 2; xi < x1i-1; xi++ {
 					if i := clamp(xi, width); i < uint(len(buf)) {
 						buf[i] += dTimesS
 					}
 				}
-				a2 := a1 + s*float32(x1i-x0i-3)
+				a2 := a1 + float32(s*float32(x1i-x0i-3))
 				if i := clamp(x1i-1, width); i < uint(len(buf)) {
-					buf[i] += d * (1 - a2 - am)
+					buf[i] += float32(d * (1 - a2 - am))
 				}
 			}
 
 			if i := clamp(x1i, width); i < uint(len(buf)) {
-				buf[i] += d * am
+				buf[i] += float32(d * am)
 			}
 		}
 

+ 54 - 43
vendor/golang.org/x/image/vector/vector_test.go

@@ -463,46 +463,57 @@ func benchGlyph(b *testing.B, colorModel byte, loose bool, height int, op draw.O
 	}
 }
 
-func BenchmarkGlyphAlpha16Over(b *testing.B)  { benchGlyph(b, 'A', false, 16, draw.Over) }
-func BenchmarkGlyphAlpha16Src(b *testing.B)   { benchGlyph(b, 'A', false, 16, draw.Src) }
-func BenchmarkGlyphAlpha32Over(b *testing.B)  { benchGlyph(b, 'A', false, 32, draw.Over) }
-func BenchmarkGlyphAlpha32Src(b *testing.B)   { benchGlyph(b, 'A', false, 32, draw.Src) }
-func BenchmarkGlyphAlpha64Over(b *testing.B)  { benchGlyph(b, 'A', false, 64, draw.Over) }
-func BenchmarkGlyphAlpha64Src(b *testing.B)   { benchGlyph(b, 'A', false, 64, draw.Src) }
-func BenchmarkGlyphAlpha128Over(b *testing.B) { benchGlyph(b, 'A', false, 128, draw.Over) }
-func BenchmarkGlyphAlpha128Src(b *testing.B)  { benchGlyph(b, 'A', false, 128, draw.Src) }
-func BenchmarkGlyphAlpha256Over(b *testing.B) { benchGlyph(b, 'A', false, 256, draw.Over) }
-func BenchmarkGlyphAlpha256Src(b *testing.B)  { benchGlyph(b, 'A', false, 256, draw.Src) }
-
-func BenchmarkGlyphAlphaLoose16Over(b *testing.B)  { benchGlyph(b, 'A', true, 16, draw.Over) }
-func BenchmarkGlyphAlphaLoose16Src(b *testing.B)   { benchGlyph(b, 'A', true, 16, draw.Src) }
-func BenchmarkGlyphAlphaLoose32Over(b *testing.B)  { benchGlyph(b, 'A', true, 32, draw.Over) }
-func BenchmarkGlyphAlphaLoose32Src(b *testing.B)   { benchGlyph(b, 'A', true, 32, draw.Src) }
-func BenchmarkGlyphAlphaLoose64Over(b *testing.B)  { benchGlyph(b, 'A', true, 64, draw.Over) }
-func BenchmarkGlyphAlphaLoose64Src(b *testing.B)   { benchGlyph(b, 'A', true, 64, draw.Src) }
-func BenchmarkGlyphAlphaLoose128Over(b *testing.B) { benchGlyph(b, 'A', true, 128, draw.Over) }
-func BenchmarkGlyphAlphaLoose128Src(b *testing.B)  { benchGlyph(b, 'A', true, 128, draw.Src) }
-func BenchmarkGlyphAlphaLoose256Over(b *testing.B) { benchGlyph(b, 'A', true, 256, draw.Over) }
-func BenchmarkGlyphAlphaLoose256Src(b *testing.B)  { benchGlyph(b, 'A', true, 256, draw.Src) }
-
-func BenchmarkGlyphRGBA16Over(b *testing.B)  { benchGlyph(b, 'R', false, 16, draw.Over) }
-func BenchmarkGlyphRGBA16Src(b *testing.B)   { benchGlyph(b, 'R', false, 16, draw.Src) }
-func BenchmarkGlyphRGBA32Over(b *testing.B)  { benchGlyph(b, 'R', false, 32, draw.Over) }
-func BenchmarkGlyphRGBA32Src(b *testing.B)   { benchGlyph(b, 'R', false, 32, draw.Src) }
-func BenchmarkGlyphRGBA64Over(b *testing.B)  { benchGlyph(b, 'R', false, 64, draw.Over) }
-func BenchmarkGlyphRGBA64Src(b *testing.B)   { benchGlyph(b, 'R', false, 64, draw.Src) }
-func BenchmarkGlyphRGBA128Over(b *testing.B) { benchGlyph(b, 'R', false, 128, draw.Over) }
-func BenchmarkGlyphRGBA128Src(b *testing.B)  { benchGlyph(b, 'R', false, 128, draw.Src) }
-func BenchmarkGlyphRGBA256Over(b *testing.B) { benchGlyph(b, 'R', false, 256, draw.Over) }
-func BenchmarkGlyphRGBA256Src(b *testing.B)  { benchGlyph(b, 'R', false, 256, draw.Src) }
-
-func BenchmarkGlyphNRGBA16Over(b *testing.B)  { benchGlyph(b, 'N', false, 16, draw.Over) }
-func BenchmarkGlyphNRGBA16Src(b *testing.B)   { benchGlyph(b, 'N', false, 16, draw.Src) }
-func BenchmarkGlyphNRGBA32Over(b *testing.B)  { benchGlyph(b, 'N', false, 32, draw.Over) }
-func BenchmarkGlyphNRGBA32Src(b *testing.B)   { benchGlyph(b, 'N', false, 32, draw.Src) }
-func BenchmarkGlyphNRGBA64Over(b *testing.B)  { benchGlyph(b, 'N', false, 64, draw.Over) }
-func BenchmarkGlyphNRGBA64Src(b *testing.B)   { benchGlyph(b, 'N', false, 64, draw.Src) }
-func BenchmarkGlyphNRGBA128Over(b *testing.B) { benchGlyph(b, 'N', false, 128, draw.Over) }
-func BenchmarkGlyphNRGBA128Src(b *testing.B)  { benchGlyph(b, 'N', false, 128, draw.Src) }
-func BenchmarkGlyphNRGBA256Over(b *testing.B) { benchGlyph(b, 'N', false, 256, draw.Over) }
-func BenchmarkGlyphNRGBA256Src(b *testing.B)  { benchGlyph(b, 'N', false, 256, draw.Src) }
+// The heights 16, 32, 64, 128, 256, 1024 include numbers both above and below
+// the floatingPointMathThreshold constant (512).
+
+func BenchmarkGlyphAlpha16Over(b *testing.B)   { benchGlyph(b, 'A', false, 16, draw.Over) }
+func BenchmarkGlyphAlpha16Src(b *testing.B)    { benchGlyph(b, 'A', false, 16, draw.Src) }
+func BenchmarkGlyphAlpha32Over(b *testing.B)   { benchGlyph(b, 'A', false, 32, draw.Over) }
+func BenchmarkGlyphAlpha32Src(b *testing.B)    { benchGlyph(b, 'A', false, 32, draw.Src) }
+func BenchmarkGlyphAlpha64Over(b *testing.B)   { benchGlyph(b, 'A', false, 64, draw.Over) }
+func BenchmarkGlyphAlpha64Src(b *testing.B)    { benchGlyph(b, 'A', false, 64, draw.Src) }
+func BenchmarkGlyphAlpha128Over(b *testing.B)  { benchGlyph(b, 'A', false, 128, draw.Over) }
+func BenchmarkGlyphAlpha128Src(b *testing.B)   { benchGlyph(b, 'A', false, 128, draw.Src) }
+func BenchmarkGlyphAlpha256Over(b *testing.B)  { benchGlyph(b, 'A', false, 256, draw.Over) }
+func BenchmarkGlyphAlpha256Src(b *testing.B)   { benchGlyph(b, 'A', false, 256, draw.Src) }
+func BenchmarkGlyphAlpha1024Over(b *testing.B) { benchGlyph(b, 'A', false, 1024, draw.Over) }
+func BenchmarkGlyphAlpha1024Src(b *testing.B)  { benchGlyph(b, 'A', false, 1024, draw.Src) }
+
+func BenchmarkGlyphAlphaLoose16Over(b *testing.B)   { benchGlyph(b, 'A', true, 16, draw.Over) }
+func BenchmarkGlyphAlphaLoose16Src(b *testing.B)    { benchGlyph(b, 'A', true, 16, draw.Src) }
+func BenchmarkGlyphAlphaLoose32Over(b *testing.B)   { benchGlyph(b, 'A', true, 32, draw.Over) }
+func BenchmarkGlyphAlphaLoose32Src(b *testing.B)    { benchGlyph(b, 'A', true, 32, draw.Src) }
+func BenchmarkGlyphAlphaLoose64Over(b *testing.B)   { benchGlyph(b, 'A', true, 64, draw.Over) }
+func BenchmarkGlyphAlphaLoose64Src(b *testing.B)    { benchGlyph(b, 'A', true, 64, draw.Src) }
+func BenchmarkGlyphAlphaLoose128Over(b *testing.B)  { benchGlyph(b, 'A', true, 128, draw.Over) }
+func BenchmarkGlyphAlphaLoose128Src(b *testing.B)   { benchGlyph(b, 'A', true, 128, draw.Src) }
+func BenchmarkGlyphAlphaLoose256Over(b *testing.B)  { benchGlyph(b, 'A', true, 256, draw.Over) }
+func BenchmarkGlyphAlphaLoose256Src(b *testing.B)   { benchGlyph(b, 'A', true, 256, draw.Src) }
+func BenchmarkGlyphAlphaLoose1024Over(b *testing.B) { benchGlyph(b, 'A', true, 1024, draw.Over) }
+func BenchmarkGlyphAlphaLoose1024Src(b *testing.B)  { benchGlyph(b, 'A', true, 1024, draw.Src) }
+
+func BenchmarkGlyphRGBA16Over(b *testing.B)   { benchGlyph(b, 'R', false, 16, draw.Over) }
+func BenchmarkGlyphRGBA16Src(b *testing.B)    { benchGlyph(b, 'R', false, 16, draw.Src) }
+func BenchmarkGlyphRGBA32Over(b *testing.B)   { benchGlyph(b, 'R', false, 32, draw.Over) }
+func BenchmarkGlyphRGBA32Src(b *testing.B)    { benchGlyph(b, 'R', false, 32, draw.Src) }
+func BenchmarkGlyphRGBA64Over(b *testing.B)   { benchGlyph(b, 'R', false, 64, draw.Over) }
+func BenchmarkGlyphRGBA64Src(b *testing.B)    { benchGlyph(b, 'R', false, 64, draw.Src) }
+func BenchmarkGlyphRGBA128Over(b *testing.B)  { benchGlyph(b, 'R', false, 128, draw.Over) }
+func BenchmarkGlyphRGBA128Src(b *testing.B)   { benchGlyph(b, 'R', false, 128, draw.Src) }
+func BenchmarkGlyphRGBA256Over(b *testing.B)  { benchGlyph(b, 'R', false, 256, draw.Over) }
+func BenchmarkGlyphRGBA256Src(b *testing.B)   { benchGlyph(b, 'R', false, 256, draw.Src) }
+func BenchmarkGlyphRGBA1024Over(b *testing.B) { benchGlyph(b, 'R', false, 1024, draw.Over) }
+func BenchmarkGlyphRGBA1024Src(b *testing.B)  { benchGlyph(b, 'R', false, 1024, draw.Src) }
+
+func BenchmarkGlyphNRGBA16Over(b *testing.B)   { benchGlyph(b, 'N', false, 16, draw.Over) }
+func BenchmarkGlyphNRGBA16Src(b *testing.B)    { benchGlyph(b, 'N', false, 16, draw.Src) }
+func BenchmarkGlyphNRGBA32Over(b *testing.B)   { benchGlyph(b, 'N', false, 32, draw.Over) }
+func BenchmarkGlyphNRGBA32Src(b *testing.B)    { benchGlyph(b, 'N', false, 32, draw.Src) }
+func BenchmarkGlyphNRGBA64Over(b *testing.B)   { benchGlyph(b, 'N', false, 64, draw.Over) }
+func BenchmarkGlyphNRGBA64Src(b *testing.B)    { benchGlyph(b, 'N', false, 64, draw.Src) }
+func BenchmarkGlyphNRGBA128Over(b *testing.B)  { benchGlyph(b, 'N', false, 128, draw.Over) }
+func BenchmarkGlyphNRGBA128Src(b *testing.B)   { benchGlyph(b, 'N', false, 128, draw.Src) }
+func BenchmarkGlyphNRGBA256Over(b *testing.B)  { benchGlyph(b, 'N', false, 256, draw.Over) }
+func BenchmarkGlyphNRGBA256Src(b *testing.B)   { benchGlyph(b, 'N', false, 256, draw.Src) }
+func BenchmarkGlyphNRGBA1024Over(b *testing.B) { benchGlyph(b, 'N', false, 1024, draw.Over) }
+func BenchmarkGlyphNRGBA1024Src(b *testing.B)  { benchGlyph(b, 'N', false, 1024, draw.Src) }

+ 10 - 0
vendor/golang.org/x/net/.gitattributes

@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text

+ 2 - 0
vendor/golang.org/x/net/.gitignore

@@ -0,0 +1,2 @@
+# Add no patterns to .hgignore except for files generated by the build.
+last-change

+ 3 - 0
vendor/golang.org/x/net/AUTHORS

@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.

+ 31 - 0
vendor/golang.org/x/net/CONTRIBUTING.md

@@ -0,0 +1,31 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+

+ 3 - 0
vendor/golang.org/x/net/CONTRIBUTORS

@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.

+ 27 - 0
vendor/golang.org/x/net/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 22 - 0
vendor/golang.org/x/net/PATENTS

@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go.  This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation.  If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.

+ 3 - 0
vendor/golang.org/x/net/README

@@ -0,0 +1,3 @@
+This repository holds supplementary Go networking libraries.
+
+To submit changes to this repository, see http://golang.org/doc/contribute.html.

+ 41 - 0
vendor/golang.org/x/net/bpf/asm.go

@@ -0,0 +1,41 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+import "fmt"
+
+// Assemble converts insts into raw instructions suitable for loading
+// into a BPF virtual machine.
+//
+// Currently, no optimization is attempted, the assembled program flow
+// is exactly as provided.
+func Assemble(insts []Instruction) ([]RawInstruction, error) {
+	ret := make([]RawInstruction, len(insts))
+	var err error
+	for i, inst := range insts {
+		ret[i], err = inst.Assemble()
+		if err != nil {
+			return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
+		}
+	}
+	return ret, nil
+}
+
+// Disassemble attempts to parse raw back into
+// Instructions. Unrecognized RawInstructions are assumed to be an
+// extension not implemented by this package, and are passed through
+// unchanged to the output. The allDecoded value reports whether insts
+// contains no RawInstructions.
+func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
+	insts = make([]Instruction, len(raw))
+	allDecoded = true
+	for i, r := range raw {
+		insts[i] = r.Disassemble()
+		if _, ok := insts[i].(RawInstruction); ok {
+			allDecoded = false
+		}
+	}
+	return insts, allDecoded
+}

+ 218 - 0
vendor/golang.org/x/net/bpf/constants.go

@@ -0,0 +1,218 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+// A Register is a register of the BPF virtual machine.
+type Register uint16
+
+const (
+	// RegA is the accumulator register. RegA is always the
+	// destination register of ALU operations.
+	RegA Register = iota
+	// RegX is the indirection register, used by LoadIndirect
+	// operations.
+	RegX
+)
+
+// An ALUOp is an arithmetic or logic operation.
+type ALUOp uint16
+
+// ALU binary operation types.
+const (
+	ALUOpAdd ALUOp = iota << 4
+	ALUOpSub
+	ALUOpMul
+	ALUOpDiv
+	ALUOpOr
+	ALUOpAnd
+	ALUOpShiftLeft
+	ALUOpShiftRight
+	aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
+	ALUOpMod
+	ALUOpXor
+)
+
+// A JumpTest is a comparison operator used in conditional jumps.
+type JumpTest uint16
+
+// Supported operators for conditional jumps.
+const (
+	// K == A
+	JumpEqual JumpTest = iota
+	// K != A
+	JumpNotEqual
+	// K > A
+	JumpGreaterThan
+	// K < A
+	JumpLessThan
+	// K >= A
+	JumpGreaterOrEqual
+	// K <= A
+	JumpLessOrEqual
+	// K & A != 0
+	JumpBitsSet
+	// K & A == 0
+	JumpBitsNotSet
+)
+
+// An Extension is a function call provided by the kernel that
+// performs advanced operations that are expensive or impossible
+// within the BPF virtual machine.
+//
+// Extensions are only implemented by the Linux kernel.
+//
+// TODO: should we prune this list? Some of these extensions seem
+// either broken or near-impossible to use correctly, whereas other
+// (len, random, ifindex) are quite useful.
+type Extension int
+
+// Extension functions available in the Linux kernel.
+const (
+	// extOffset is the negative maximum number of instructions used
+	// to load instructions by overloading the K argument.
+	extOffset = -0x1000
+	// ExtLen returns the length of the packet.
+	ExtLen Extension = 1
+	// ExtProto returns the packet's L3 protocol type.
+	ExtProto Extension = 0
+	// ExtType returns the packet's type (skb->pkt_type in the kernel)
+	//
+	// TODO: better documentation. How nice an API do we want to
+	// provide for these esoteric extensions?
+	ExtType Extension = 4
+	// ExtPayloadOffset returns the offset of the packet payload, or
+	// the first protocol header that the kernel does not know how to
+	// parse.
+	ExtPayloadOffset Extension = 52
+	// ExtInterfaceIndex returns the index of the interface on which
+	// the packet was received.
+	ExtInterfaceIndex Extension = 8
+	// ExtNetlinkAttr returns the netlink attribute of type X at
+	// offset A.
+	ExtNetlinkAttr Extension = 12
+	// ExtNetlinkAttrNested returns the nested netlink attribute of
+	// type X at offset A.
+	ExtNetlinkAttrNested Extension = 16
+	// ExtMark returns the packet's mark value.
+	ExtMark Extension = 20
+	// ExtQueue returns the packet's assigned hardware queue.
+	ExtQueue Extension = 24
+	// ExtLinkLayerType returns the packet's hardware address type
+	// (e.g. Ethernet, Infiniband).
+	ExtLinkLayerType Extension = 28
+	// ExtRXHash returns the packets receive hash.
+	//
+	// TODO: figure out what this rxhash actually is.
+	ExtRXHash Extension = 32
+	// ExtCPUID returns the ID of the CPU processing the current
+	// packet.
+	ExtCPUID Extension = 36
+	// ExtVLANTag returns the packet's VLAN tag.
+	ExtVLANTag Extension = 44
+	// ExtVLANTagPresent returns non-zero if the packet has a VLAN
+	// tag.
+	//
+	// TODO: I think this might be a lie: it reads bit 0x1000 of the
+	// VLAN header, which changed meaning in recent revisions of the
+	// spec - this extension may now return meaningless information.
+	ExtVLANTagPresent Extension = 48
+	// ExtVLANProto returns 0x8100 if the frame has a VLAN header,
+	// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
+	// other value if no VLAN information is present.
+	ExtVLANProto Extension = 60
+	// ExtRand returns a uniformly random uint32.
+	ExtRand Extension = 56
+)
+
+// The following gives names to various bit patterns used in opcode construction.
+
+const (
+	opMaskCls uint16 = 0x7
+	// opClsLoad masks
+	opMaskLoadDest  = 0x01
+	opMaskLoadWidth = 0x18
+	opMaskLoadMode  = 0xe0
+	// opClsALU
+	opMaskOperandSrc = 0x08
+	opMaskOperator   = 0xf0
+	// opClsJump
+	opMaskJumpConst = 0x0f
+	opMaskJumpCond  = 0xf0
+)
+
+const (
+	// +---------------+-----------------+---+---+---+
+	// | AddrMode (3b) | LoadWidth (2b)  | 0 | 0 | 0 |
+	// +---------------+-----------------+---+---+---+
+	opClsLoadA uint16 = iota
+	// +---------------+-----------------+---+---+---+
+	// | AddrMode (3b) | LoadWidth (2b)  | 0 | 0 | 1 |
+	// +---------------+-----------------+---+---+---+
+	opClsLoadX
+	// +---+---+---+---+---+---+---+---+
+	// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
+	// +---+---+---+---+---+---+---+---+
+	opClsStoreA
+	// +---+---+---+---+---+---+---+---+
+	// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
+	// +---+---+---+---+---+---+---+---+
+	opClsStoreX
+	// +---------------+-----------------+---+---+---+
+	// | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
+	// +---------------+-----------------+---+---+---+
+	opClsALU
+	// +-----------------------------+---+---+---+---+
+	// |      TestOperator (4b)      | 0 | 1 | 0 | 1 |
+	// +-----------------------------+---+---+---+---+
+	opClsJump
+	// +---+-------------------------+---+---+---+---+
+	// | 0 | 0 | 0 |   RetSrc (1b)   | 0 | 1 | 1 | 0 |
+	// +---+-------------------------+---+---+---+---+
+	opClsReturn
+	// +---+-------------------------+---+---+---+---+
+	// | 0 | 0 | 0 |  TXAorTAX (1b)  | 0 | 1 | 1 | 1 |
+	// +---+-------------------------+---+---+---+---+
+	opClsMisc
+)
+
+const (
+	opAddrModeImmediate uint16 = iota << 5
+	opAddrModeAbsolute
+	opAddrModeIndirect
+	opAddrModeScratch
+	opAddrModePacketLen // actually an extension, not an addressing mode.
+	opAddrModeMemShift
+)
+
+const (
+	opLoadWidth4 uint16 = iota << 3
+	opLoadWidth2
+	opLoadWidth1
+)
+
+// Operator defined by ALUOp*
+
+const (
+	opALUSrcConstant uint16 = iota << 3
+	opALUSrcX
+)
+
+const (
+	opJumpAlways = iota << 4
+	opJumpEqual
+	opJumpGT
+	opJumpGE
+	opJumpSet
+)
+
+const (
+	opRetSrcConstant uint16 = iota << 4
+	opRetSrcA
+)
+
+const (
+	opMiscTAX = 0x00
+	opMiscTXA = 0x80
+)

+ 82 - 0
vendor/golang.org/x/net/bpf/doc.go

@@ -0,0 +1,82 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Package bpf implements marshaling and unmarshaling of programs for the
+Berkeley Packet Filter virtual machine, and provides a Go implementation
+of the virtual machine.
+
+BPF's main use is to specify a packet filter for network taps, so that
+the kernel doesn't have to expensively copy every packet it sees to
+userspace. However, it's been repurposed to other areas where running
+user code in-kernel is needed. For example, Linux's seccomp uses BPF
+to apply security policies to system calls. For simplicity, this
+documentation refers only to packets, but other uses of BPF have their
+own data payloads.
+
+BPF programs run in a restricted virtual machine. It has almost no
+access to kernel functions, and while conditional branches are
+allowed, they can only jump forwards, to guarantee that there are no
+infinite loops.
+
+The virtual machine
+
+The BPF VM is an accumulator machine. Its main register, called
+register A, is an implicit source and destination in all arithmetic
+and logic operations. The machine also has 16 scratch registers for
+temporary storage, and an indirection register (register X) for
+indirect memory access. All registers are 32 bits wide.
+
+Each run of a BPF program is given one packet, which is placed in the
+VM's read-only "main memory". LoadAbsolute and LoadIndirect
+instructions can fetch up to 32 bits at a time into register A for
+examination.
+
+The goal of a BPF program is to produce and return a verdict (uint32),
+which tells the kernel what to do with the packet. In the context of
+packet filtering, the returned value is the number of bytes of the
+packet to forward to userspace, or 0 to ignore the packet. Other
+contexts like seccomp define their own return values.
+
+In order to simplify programs, attempts to read past the end of the
+packet terminate the program execution with a verdict of 0 (ignore
+packet). This means that the vast majority of BPF programs don't need
+to do any explicit bounds checking.
+
+In addition to the bytes of the packet, some BPF programs have access
+to extensions, which are essentially calls to kernel utility
+functions. Currently, the only extensions supported by this package
+are the Linux packet filter extensions.
+
+Examples
+
+This packet filter selects all ARP packets.
+
+	bpf.Assemble([]bpf.Instruction{
+		// Load "EtherType" field from the ethernet header.
+		bpf.LoadAbsolute{Off: 12, Size: 2},
+		// Skip over the next instruction if EtherType is not ARP.
+		bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1},
+		// Verdict is "send up to 4k of the packet to userspace."
+		bpf.RetConstant{Val: 4096},
+		// Verdict is "ignore packet."
+		bpf.RetConstant{Val: 0},
+	})
+
+This packet filter captures a random 1% sample of traffic.
+
+	bpf.Assemble([]bpf.Instruction{
+		// Get a 32-bit random number from the Linux kernel.
+		bpf.LoadExtension{Num: bpf.ExtRand},
+		// 1% dice roll?
+		bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1},
+		// Capture.
+		bpf.RetConstant{Val: 4096},
+		// Ignore.
+		bpf.RetConstant{Val: 0},
+	})
+
+*/
+package bpf // import "golang.org/x/net/bpf"

+ 704 - 0
vendor/golang.org/x/net/bpf/instructions.go

@@ -0,0 +1,704 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+import "fmt"
+
+// An Instruction is one instruction executed by the BPF virtual
+// machine.
+type Instruction interface {
+	// Assemble assembles the Instruction into a RawInstruction.
+	Assemble() (RawInstruction, error)
+}
+
+// A RawInstruction is a raw BPF virtual machine instruction.
+type RawInstruction struct {
+	// Operation to execute.
+	Op uint16
+	// For conditional jump instructions, the number of instructions
+	// to skip if the condition is true/false.
+	Jt uint8
+	Jf uint8
+	// Constant parameter. The meaning depends on the Op.
+	K uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
+
+// Disassemble parses ri into an Instruction and returns it. If ri is
+// not recognized by this package, ri itself is returned.
+func (ri RawInstruction) Disassemble() Instruction {
+	switch ri.Op & opMaskCls {
+	case opClsLoadA, opClsLoadX:
+		reg := Register(ri.Op & opMaskLoadDest)
+		sz := 0
+		switch ri.Op & opMaskLoadWidth {
+		case opLoadWidth4:
+			sz = 4
+		case opLoadWidth2:
+			sz = 2
+		case opLoadWidth1:
+			sz = 1
+		default:
+			return ri
+		}
+		switch ri.Op & opMaskLoadMode {
+		case opAddrModeImmediate:
+			if sz != 4 {
+				return ri
+			}
+			return LoadConstant{Dst: reg, Val: ri.K}
+		case opAddrModeScratch:
+			if sz != 4 || ri.K > 15 {
+				return ri
+			}
+			return LoadScratch{Dst: reg, N: int(ri.K)}
+		case opAddrModeAbsolute:
+			if ri.K > extOffset+0xffffffff {
+				return LoadExtension{Num: Extension(-extOffset + ri.K)}
+			}
+			return LoadAbsolute{Size: sz, Off: ri.K}
+		case opAddrModeIndirect:
+			return LoadIndirect{Size: sz, Off: ri.K}
+		case opAddrModePacketLen:
+			if sz != 4 {
+				return ri
+			}
+			return LoadExtension{Num: ExtLen}
+		case opAddrModeMemShift:
+			return LoadMemShift{Off: ri.K}
+		default:
+			return ri
+		}
+
+	case opClsStoreA:
+		if ri.Op != opClsStoreA || ri.K > 15 {
+			return ri
+		}
+		return StoreScratch{Src: RegA, N: int(ri.K)}
+
+	case opClsStoreX:
+		if ri.Op != opClsStoreX || ri.K > 15 {
+			return ri
+		}
+		return StoreScratch{Src: RegX, N: int(ri.K)}
+
+	case opClsALU:
+		switch op := ALUOp(ri.Op & opMaskOperator); op {
+		case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
+			if ri.Op&opMaskOperandSrc != 0 {
+				return ALUOpX{Op: op}
+			}
+			return ALUOpConstant{Op: op, Val: ri.K}
+		case aluOpNeg:
+			return NegateA{}
+		default:
+			return ri
+		}
+
+	case opClsJump:
+		if ri.Op&opMaskJumpConst != opClsJump {
+			return ri
+		}
+		switch ri.Op & opMaskJumpCond {
+		case opJumpAlways:
+			return Jump{Skip: ri.K}
+		case opJumpEqual:
+			if ri.Jt == 0 {
+				return JumpIf{
+					Cond:      JumpNotEqual,
+					Val:       ri.K,
+					SkipTrue:  ri.Jf,
+					SkipFalse: 0,
+				}
+			}
+			return JumpIf{
+				Cond:      JumpEqual,
+				Val:       ri.K,
+				SkipTrue:  ri.Jt,
+				SkipFalse: ri.Jf,
+			}
+		case opJumpGT:
+			if ri.Jt == 0 {
+				return JumpIf{
+					Cond:      JumpLessOrEqual,
+					Val:       ri.K,
+					SkipTrue:  ri.Jf,
+					SkipFalse: 0,
+				}
+			}
+			return JumpIf{
+				Cond:      JumpGreaterThan,
+				Val:       ri.K,
+				SkipTrue:  ri.Jt,
+				SkipFalse: ri.Jf,
+			}
+		case opJumpGE:
+			if ri.Jt == 0 {
+				return JumpIf{
+					Cond:      JumpLessThan,
+					Val:       ri.K,
+					SkipTrue:  ri.Jf,
+					SkipFalse: 0,
+				}
+			}
+			return JumpIf{
+				Cond:      JumpGreaterOrEqual,
+				Val:       ri.K,
+				SkipTrue:  ri.Jt,
+				SkipFalse: ri.Jf,
+			}
+		case opJumpSet:
+			return JumpIf{
+				Cond:      JumpBitsSet,
+				Val:       ri.K,
+				SkipTrue:  ri.Jt,
+				SkipFalse: ri.Jf,
+			}
+		default:
+			return ri
+		}
+
+	case opClsReturn:
+		switch ri.Op {
+		case opClsReturn | opRetSrcA:
+			return RetA{}
+		case opClsReturn | opRetSrcConstant:
+			return RetConstant{Val: ri.K}
+		default:
+			return ri
+		}
+
+	case opClsMisc:
+		switch ri.Op {
+		case opClsMisc | opMiscTAX:
+			return TAX{}
+		case opClsMisc | opMiscTXA:
+			return TXA{}
+		default:
+			return ri
+		}
+
+	default:
+		panic("unreachable") // switch is exhaustive on the bit pattern
+	}
+}
+
+// LoadConstant loads Val into register Dst.
+type LoadConstant struct {
+	Dst Register
+	Val uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadConstant) Assemble() (RawInstruction, error) {
+	return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
+}
+
+// String returns the the instruction in assembler notation.
+func (a LoadConstant) String() string {
+	switch a.Dst {
+	case RegA:
+		return fmt.Sprintf("ld #%d", a.Val)
+	case RegX:
+		return fmt.Sprintf("ldx #%d", a.Val)
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// LoadScratch loads scratch[N] into register Dst.
+type LoadScratch struct {
+	Dst Register
+	N   int // 0-15
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadScratch) Assemble() (RawInstruction, error) {
+	if a.N < 0 || a.N > 15 {
+		return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
+	}
+	return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
+}
+
+// String returns the the instruction in assembler notation.
+func (a LoadScratch) String() string {
+	switch a.Dst {
+	case RegA:
+		return fmt.Sprintf("ld M[%d]", a.N)
+	case RegX:
+		return fmt.Sprintf("ldx M[%d]", a.N)
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
+// register A.
+type LoadAbsolute struct {
+	Off  uint32
+	Size int // 1, 2 or 4
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadAbsolute) Assemble() (RawInstruction, error) {
+	return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
+}
+
+// String returns the the instruction in assembler notation.
+func (a LoadAbsolute) String() string {
+	switch a.Size {
+	case 1: // byte
+		return fmt.Sprintf("ldb [%d]", a.Off)
+	case 2: // half word
+		return fmt.Sprintf("ldh [%d]", a.Off)
+	case 4: // word
+		if a.Off > extOffset+0xffffffff {
+			return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
+		}
+		return fmt.Sprintf("ld [%d]", a.Off)
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
+// into register A.
+type LoadIndirect struct {
+	Off  uint32
+	Size int // 1, 2 or 4
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadIndirect) Assemble() (RawInstruction, error) {
+	return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
+}
+
+// String returns the the instruction in assembler notation.
+func (a LoadIndirect) String() string {
+	switch a.Size {
+	case 1: // byte
+		return fmt.Sprintf("ldb [x + %d]", a.Off)
+	case 2: // half word
+		return fmt.Sprintf("ldh [x + %d]", a.Off)
+	case 4: // word
+		return fmt.Sprintf("ld [x + %d]", a.Off)
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
+// by 4 and stores the result in register X.
+//
+// This instruction is mainly useful to load into X the length of an
+// IPv4 packet header in a single instruction, rather than have to do
+// the arithmetic on the header's first byte by hand.
+type LoadMemShift struct {
+	Off uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadMemShift) Assemble() (RawInstruction, error) {
+	return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
+}
+
+// String returns the the instruction in assembler notation.
+func (a LoadMemShift) String() string {
+	return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
+}
+
+// LoadExtension invokes a linux-specific extension and stores the
+// result in register A.
+type LoadExtension struct {
+	Num Extension
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadExtension) Assemble() (RawInstruction, error) {
+	if a.Num == ExtLen {
+		return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
+	}
+	return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
+}
+
+// String returns the the instruction in assembler notation.
+func (a LoadExtension) String() string {
+	switch a.Num {
+	case ExtLen:
+		return "ld #len"
+	case ExtProto:
+		return "ld #proto"
+	case ExtType:
+		return "ld #type"
+	case ExtPayloadOffset:
+		return "ld #poff"
+	case ExtInterfaceIndex:
+		return "ld #ifidx"
+	case ExtNetlinkAttr:
+		return "ld #nla"
+	case ExtNetlinkAttrNested:
+		return "ld #nlan"
+	case ExtMark:
+		return "ld #mark"
+	case ExtQueue:
+		return "ld #queue"
+	case ExtLinkLayerType:
+		return "ld #hatype"
+	case ExtRXHash:
+		return "ld #rxhash"
+	case ExtCPUID:
+		return "ld #cpu"
+	case ExtVLANTag:
+		return "ld #vlan_tci"
+	case ExtVLANTagPresent:
+		return "ld #vlan_avail"
+	case ExtVLANProto:
+		return "ld #vlan_tpid"
+	case ExtRand:
+		return "ld #rand"
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// StoreScratch stores register Src into scratch[N].
+type StoreScratch struct {
+	Src Register
+	N   int // 0-15
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a StoreScratch) Assemble() (RawInstruction, error) {
+	if a.N < 0 || a.N > 15 {
+		return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
+	}
+	var op uint16
+	switch a.Src {
+	case RegA:
+		op = opClsStoreA
+	case RegX:
+		op = opClsStoreX
+	default:
+		return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
+	}
+
+	return RawInstruction{
+		Op: op,
+		K:  uint32(a.N),
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a StoreScratch) String() string {
+	switch a.Src {
+	case RegA:
+		return fmt.Sprintf("st M[%d]", a.N)
+	case RegX:
+		return fmt.Sprintf("stx M[%d]", a.N)
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// ALUOpConstant executes A = A <Op> Val.
+type ALUOpConstant struct {
+	Op  ALUOp
+	Val uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a ALUOpConstant) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsALU | opALUSrcConstant | uint16(a.Op),
+		K:  a.Val,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a ALUOpConstant) String() string {
+	switch a.Op {
+	case ALUOpAdd:
+		return fmt.Sprintf("add #%d", a.Val)
+	case ALUOpSub:
+		return fmt.Sprintf("sub #%d", a.Val)
+	case ALUOpMul:
+		return fmt.Sprintf("mul #%d", a.Val)
+	case ALUOpDiv:
+		return fmt.Sprintf("div #%d", a.Val)
+	case ALUOpMod:
+		return fmt.Sprintf("mod #%d", a.Val)
+	case ALUOpAnd:
+		return fmt.Sprintf("and #%d", a.Val)
+	case ALUOpOr:
+		return fmt.Sprintf("or #%d", a.Val)
+	case ALUOpXor:
+		return fmt.Sprintf("xor #%d", a.Val)
+	case ALUOpShiftLeft:
+		return fmt.Sprintf("lsh #%d", a.Val)
+	case ALUOpShiftRight:
+		return fmt.Sprintf("rsh #%d", a.Val)
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// ALUOpX executes A = A <Op> X
+type ALUOpX struct {
+	Op ALUOp
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a ALUOpX) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsALU | opALUSrcX | uint16(a.Op),
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a ALUOpX) String() string {
+	switch a.Op {
+	case ALUOpAdd:
+		return "add x"
+	case ALUOpSub:
+		return "sub x"
+	case ALUOpMul:
+		return "mul x"
+	case ALUOpDiv:
+		return "div x"
+	case ALUOpMod:
+		return "mod x"
+	case ALUOpAnd:
+		return "and x"
+	case ALUOpOr:
+		return "or x"
+	case ALUOpXor:
+		return "xor x"
+	case ALUOpShiftLeft:
+		return "lsh x"
+	case ALUOpShiftRight:
+		return "rsh x"
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+// NegateA executes A = -A.
+type NegateA struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a NegateA) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsALU | uint16(aluOpNeg),
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a NegateA) String() string {
+	return fmt.Sprintf("neg")
+}
+
+// Jump skips the following Skip instructions in the program.
+type Jump struct {
+	Skip uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a Jump) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsJump | opJumpAlways,
+		K:  a.Skip,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a Jump) String() string {
+	return fmt.Sprintf("ja %d", a.Skip)
+}
+
+// JumpIf skips the following Skip instructions in the program if A
+// <Cond> Val is true.
+type JumpIf struct {
+	Cond      JumpTest
+	Val       uint32
+	SkipTrue  uint8
+	SkipFalse uint8
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a JumpIf) Assemble() (RawInstruction, error) {
+	var (
+		cond uint16
+		flip bool
+	)
+	switch a.Cond {
+	case JumpEqual:
+		cond = opJumpEqual
+	case JumpNotEqual:
+		cond, flip = opJumpEqual, true
+	case JumpGreaterThan:
+		cond = opJumpGT
+	case JumpLessThan:
+		cond, flip = opJumpGE, true
+	case JumpGreaterOrEqual:
+		cond = opJumpGE
+	case JumpLessOrEqual:
+		cond, flip = opJumpGT, true
+	case JumpBitsSet:
+		cond = opJumpSet
+	case JumpBitsNotSet:
+		cond, flip = opJumpSet, true
+	default:
+		return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
+	}
+	jt, jf := a.SkipTrue, a.SkipFalse
+	if flip {
+		jt, jf = jf, jt
+	}
+	return RawInstruction{
+		Op: opClsJump | cond,
+		Jt: jt,
+		Jf: jf,
+		K:  a.Val,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a JumpIf) String() string {
+	switch a.Cond {
+	// K == A
+	case JumpEqual:
+		return conditionalJump(a, "jeq", "jneq")
+	// K != A
+	case JumpNotEqual:
+		return fmt.Sprintf("jneq #%d,%d", a.Val, a.SkipTrue)
+	// K > A
+	case JumpGreaterThan:
+		return conditionalJump(a, "jgt", "jle")
+	// K < A
+	case JumpLessThan:
+		return fmt.Sprintf("jlt #%d,%d", a.Val, a.SkipTrue)
+	// K >= A
+	case JumpGreaterOrEqual:
+		return conditionalJump(a, "jge", "jlt")
+	// K <= A
+	case JumpLessOrEqual:
+		return fmt.Sprintf("jle #%d,%d", a.Val, a.SkipTrue)
+	// K & A != 0
+	case JumpBitsSet:
+		if a.SkipFalse > 0 {
+			return fmt.Sprintf("jset #%d,%d,%d", a.Val, a.SkipTrue, a.SkipFalse)
+		}
+		return fmt.Sprintf("jset #%d,%d", a.Val, a.SkipTrue)
+	// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
+	case JumpBitsNotSet:
+		return JumpIf{Cond: JumpBitsSet, SkipTrue: a.SkipFalse, SkipFalse: a.SkipTrue, Val: a.Val}.String()
+	default:
+		return fmt.Sprintf("unknown instruction: %#v", a)
+	}
+}
+
+func conditionalJump(inst JumpIf, positiveJump, negativeJump string) string {
+	if inst.SkipTrue > 0 {
+		if inst.SkipFalse > 0 {
+			return fmt.Sprintf("%s #%d,%d,%d", positiveJump, inst.Val, inst.SkipTrue, inst.SkipFalse)
+		}
+		return fmt.Sprintf("%s #%d,%d", positiveJump, inst.Val, inst.SkipTrue)
+	}
+	return fmt.Sprintf("%s #%d,%d", negativeJump, inst.Val, inst.SkipFalse)
+}
+
+// RetA exits the BPF program, returning the value of register A.
+type RetA struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a RetA) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsReturn | opRetSrcA,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a RetA) String() string {
+	return fmt.Sprintf("ret a")
+}
+
+// RetConstant exits the BPF program, returning a constant value.
+type RetConstant struct {
+	Val uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a RetConstant) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsReturn | opRetSrcConstant,
+		K:  a.Val,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a RetConstant) String() string {
+	return fmt.Sprintf("ret #%d", a.Val)
+}
+
+// TXA copies the value of register X to register A.
+type TXA struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a TXA) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsMisc | opMiscTXA,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a TXA) String() string {
+	return fmt.Sprintf("txa")
+}
+
+// TAX copies the value of register A to register X.
+type TAX struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a TAX) Assemble() (RawInstruction, error) {
+	return RawInstruction{
+		Op: opClsMisc | opMiscTAX,
+	}, nil
+}
+
+// String returns the the instruction in assembler notation.
+func (a TAX) String() string {
+	return fmt.Sprintf("tax")
+}
+
+func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
+	var (
+		cls uint16
+		sz  uint16
+	)
+	switch dst {
+	case RegA:
+		cls = opClsLoadA
+	case RegX:
+		cls = opClsLoadX
+	default:
+		return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
+	}
+	switch loadSize {
+	case 1:
+		sz = opLoadWidth1
+	case 2:
+		sz = opLoadWidth2
+	case 4:
+		sz = opLoadWidth4
+	default:
+		return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
+	}
+	return RawInstruction{
+		Op: cls | sz | mode,
+		K:  k,
+	}, nil
+}

+ 525 - 0
vendor/golang.org/x/net/bpf/instructions_test.go

@@ -0,0 +1,525 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+import (
+	"fmt"
+	"io/ioutil"
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+// This is a direct translation of the program in
+// testdata/all_instructions.txt.
+var allInstructions = []Instruction{
+	LoadConstant{Dst: RegA, Val: 42},
+	LoadConstant{Dst: RegX, Val: 42},
+
+	LoadScratch{Dst: RegA, N: 3},
+	LoadScratch{Dst: RegX, N: 3},
+
+	LoadAbsolute{Off: 42, Size: 1},
+	LoadAbsolute{Off: 42, Size: 2},
+	LoadAbsolute{Off: 42, Size: 4},
+
+	LoadIndirect{Off: 42, Size: 1},
+	LoadIndirect{Off: 42, Size: 2},
+	LoadIndirect{Off: 42, Size: 4},
+
+	LoadMemShift{Off: 42},
+
+	LoadExtension{Num: ExtLen},
+	LoadExtension{Num: ExtProto},
+	LoadExtension{Num: ExtType},
+	LoadExtension{Num: ExtRand},
+
+	StoreScratch{Src: RegA, N: 3},
+	StoreScratch{Src: RegX, N: 3},
+
+	ALUOpConstant{Op: ALUOpAdd, Val: 42},
+	ALUOpConstant{Op: ALUOpSub, Val: 42},
+	ALUOpConstant{Op: ALUOpMul, Val: 42},
+	ALUOpConstant{Op: ALUOpDiv, Val: 42},
+	ALUOpConstant{Op: ALUOpOr, Val: 42},
+	ALUOpConstant{Op: ALUOpAnd, Val: 42},
+	ALUOpConstant{Op: ALUOpShiftLeft, Val: 42},
+	ALUOpConstant{Op: ALUOpShiftRight, Val: 42},
+	ALUOpConstant{Op: ALUOpMod, Val: 42},
+	ALUOpConstant{Op: ALUOpXor, Val: 42},
+
+	ALUOpX{Op: ALUOpAdd},
+	ALUOpX{Op: ALUOpSub},
+	ALUOpX{Op: ALUOpMul},
+	ALUOpX{Op: ALUOpDiv},
+	ALUOpX{Op: ALUOpOr},
+	ALUOpX{Op: ALUOpAnd},
+	ALUOpX{Op: ALUOpShiftLeft},
+	ALUOpX{Op: ALUOpShiftRight},
+	ALUOpX{Op: ALUOpMod},
+	ALUOpX{Op: ALUOpXor},
+
+	NegateA{},
+
+	Jump{Skip: 10},
+	JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8, SkipFalse: 9},
+	JumpIf{Cond: JumpNotEqual, Val: 42, SkipTrue: 8},
+	JumpIf{Cond: JumpLessThan, Val: 42, SkipTrue: 7},
+	JumpIf{Cond: JumpLessOrEqual, Val: 42, SkipTrue: 6},
+	JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4, SkipFalse: 5},
+	JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3, SkipFalse: 4},
+	JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
+
+	TAX{},
+	TXA{},
+
+	RetA{},
+	RetConstant{Val: 42},
+}
+var allInstructionsExpected = "testdata/all_instructions.bpf"
+
+// Check that we produce the same output as the canonical bpf_asm
+// linux kernel tool.
+func TestInterop(t *testing.T) {
+	out, err := Assemble(allInstructions)
+	if err != nil {
+		t.Fatalf("assembly of allInstructions program failed: %s", err)
+	}
+	t.Logf("Assembled program is %d instructions long", len(out))
+
+	bs, err := ioutil.ReadFile(allInstructionsExpected)
+	if err != nil {
+		t.Fatalf("reading %s: %s", allInstructionsExpected, err)
+	}
+	// First statement is the number of statements, last statement is
+	// empty. We just ignore both and rely on slice length.
+	stmts := strings.Split(string(bs), ",")
+	if len(stmts)-2 != len(out) {
+		t.Fatalf("test program lengths don't match: %s has %d, Go implementation has %d", allInstructionsExpected, len(stmts)-2, len(allInstructions))
+	}
+
+	for i, stmt := range stmts[1 : len(stmts)-2] {
+		nums := strings.Split(stmt, " ")
+		if len(nums) != 4 {
+			t.Fatalf("malformed instruction %d in %s: %s", i+1, allInstructionsExpected, stmt)
+		}
+
+		actual := out[i]
+
+		op, err := strconv.ParseUint(nums[0], 10, 16)
+		if err != nil {
+			t.Fatalf("malformed opcode %s in instruction %d of %s", nums[0], i+1, allInstructionsExpected)
+		}
+		if actual.Op != uint16(op) {
+			t.Errorf("opcode mismatch on instruction %d (%#v): got 0x%02x, want 0x%02x", i+1, allInstructions[i], actual.Op, op)
+		}
+
+		jt, err := strconv.ParseUint(nums[1], 10, 8)
+		if err != nil {
+			t.Fatalf("malformed jt offset %s in instruction %d of %s", nums[1], i+1, allInstructionsExpected)
+		}
+		if actual.Jt != uint8(jt) {
+			t.Errorf("jt mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.Jt, jt)
+		}
+
+		jf, err := strconv.ParseUint(nums[2], 10, 8)
+		if err != nil {
+			t.Fatalf("malformed jf offset %s in instruction %d of %s", nums[2], i+1, allInstructionsExpected)
+		}
+		if actual.Jf != uint8(jf) {
+			t.Errorf("jf mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.Jf, jf)
+		}
+
+		k, err := strconv.ParseUint(nums[3], 10, 32)
+		if err != nil {
+			t.Fatalf("malformed constant %s in instruction %d of %s", nums[3], i+1, allInstructionsExpected)
+		}
+		if actual.K != uint32(k) {
+			t.Errorf("constant mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.K, k)
+		}
+	}
+}
+
+// Check that assembly and disassembly match each other.
+func TestAsmDisasm(t *testing.T) {
+	prog1, err := Assemble(allInstructions)
+	if err != nil {
+		t.Fatalf("assembly of allInstructions program failed: %s", err)
+	}
+	t.Logf("Assembled program is %d instructions long", len(prog1))
+
+	got, allDecoded := Disassemble(prog1)
+	if !allDecoded {
+		t.Errorf("Disassemble(Assemble(allInstructions)) produced unrecognized instructions:")
+		for i, inst := range got {
+			if r, ok := inst.(RawInstruction); ok {
+				t.Logf("  insn %d, %#v --> %#v", i+1, allInstructions[i], r)
+			}
+		}
+	}
+
+	if len(allInstructions) != len(got) {
+		t.Fatalf("disassembly changed program size: %d insns before, %d insns after", len(allInstructions), len(got))
+	}
+	if !reflect.DeepEqual(allInstructions, got) {
+		t.Errorf("program mutated by disassembly:")
+		for i := range got {
+			if !reflect.DeepEqual(allInstructions[i], got[i]) {
+				t.Logf("  insn %d, s: %#v, p1: %#v, got: %#v", i+1, allInstructions[i], prog1[i], got[i])
+			}
+		}
+	}
+}
+
+type InvalidInstruction struct{}
+
+func (a InvalidInstruction) Assemble() (RawInstruction, error) {
+	return RawInstruction{}, fmt.Errorf("Invalid Instruction")
+}
+
+func (a InvalidInstruction) String() string {
+	return fmt.Sprintf("unknown instruction: %#v", a)
+}
+
+func TestString(t *testing.T) {
+	testCases := []struct {
+		instruction Instruction
+		assembler   string
+	}{
+		{
+			instruction: LoadConstant{Dst: RegA, Val: 42},
+			assembler:   "ld #42",
+		},
+		{
+			instruction: LoadConstant{Dst: RegX, Val: 42},
+			assembler:   "ldx #42",
+		},
+		{
+			instruction: LoadConstant{Dst: 0xffff, Val: 42},
+			assembler:   "unknown instruction: bpf.LoadConstant{Dst:0xffff, Val:0x2a}",
+		},
+		{
+			instruction: LoadScratch{Dst: RegA, N: 3},
+			assembler:   "ld M[3]",
+		},
+		{
+			instruction: LoadScratch{Dst: RegX, N: 3},
+			assembler:   "ldx M[3]",
+		},
+		{
+			instruction: LoadScratch{Dst: 0xffff, N: 3},
+			assembler:   "unknown instruction: bpf.LoadScratch{Dst:0xffff, N:3}",
+		},
+		{
+			instruction: LoadAbsolute{Off: 42, Size: 1},
+			assembler:   "ldb [42]",
+		},
+		{
+			instruction: LoadAbsolute{Off: 42, Size: 2},
+			assembler:   "ldh [42]",
+		},
+		{
+			instruction: LoadAbsolute{Off: 42, Size: 4},
+			assembler:   "ld [42]",
+		},
+		{
+			instruction: LoadAbsolute{Off: 42, Size: -1},
+			assembler:   "unknown instruction: bpf.LoadAbsolute{Off:0x2a, Size:-1}",
+		},
+		{
+			instruction: LoadIndirect{Off: 42, Size: 1},
+			assembler:   "ldb [x + 42]",
+		},
+		{
+			instruction: LoadIndirect{Off: 42, Size: 2},
+			assembler:   "ldh [x + 42]",
+		},
+		{
+			instruction: LoadIndirect{Off: 42, Size: 4},
+			assembler:   "ld [x + 42]",
+		},
+		{
+			instruction: LoadIndirect{Off: 42, Size: -1},
+			assembler:   "unknown instruction: bpf.LoadIndirect{Off:0x2a, Size:-1}",
+		},
+		{
+			instruction: LoadMemShift{Off: 42},
+			assembler:   "ldx 4*([42]&0xf)",
+		},
+		{
+			instruction: LoadExtension{Num: ExtLen},
+			assembler:   "ld #len",
+		},
+		{
+			instruction: LoadExtension{Num: ExtProto},
+			assembler:   "ld #proto",
+		},
+		{
+			instruction: LoadExtension{Num: ExtType},
+			assembler:   "ld #type",
+		},
+		{
+			instruction: LoadExtension{Num: ExtPayloadOffset},
+			assembler:   "ld #poff",
+		},
+		{
+			instruction: LoadExtension{Num: ExtInterfaceIndex},
+			assembler:   "ld #ifidx",
+		},
+		{
+			instruction: LoadExtension{Num: ExtNetlinkAttr},
+			assembler:   "ld #nla",
+		},
+		{
+			instruction: LoadExtension{Num: ExtNetlinkAttrNested},
+			assembler:   "ld #nlan",
+		},
+		{
+			instruction: LoadExtension{Num: ExtMark},
+			assembler:   "ld #mark",
+		},
+		{
+			instruction: LoadExtension{Num: ExtQueue},
+			assembler:   "ld #queue",
+		},
+		{
+			instruction: LoadExtension{Num: ExtLinkLayerType},
+			assembler:   "ld #hatype",
+		},
+		{
+			instruction: LoadExtension{Num: ExtRXHash},
+			assembler:   "ld #rxhash",
+		},
+		{
+			instruction: LoadExtension{Num: ExtCPUID},
+			assembler:   "ld #cpu",
+		},
+		{
+			instruction: LoadExtension{Num: ExtVLANTag},
+			assembler:   "ld #vlan_tci",
+		},
+		{
+			instruction: LoadExtension{Num: ExtVLANTagPresent},
+			assembler:   "ld #vlan_avail",
+		},
+		{
+			instruction: LoadExtension{Num: ExtVLANProto},
+			assembler:   "ld #vlan_tpid",
+		},
+		{
+			instruction: LoadExtension{Num: ExtRand},
+			assembler:   "ld #rand",
+		},
+		{
+			instruction: LoadAbsolute{Off: 0xfffff038, Size: 4},
+			assembler:   "ld #rand",
+		},
+		{
+			instruction: LoadExtension{Num: 0xfff},
+			assembler:   "unknown instruction: bpf.LoadExtension{Num:4095}",
+		},
+		{
+			instruction: StoreScratch{Src: RegA, N: 3},
+			assembler:   "st M[3]",
+		},
+		{
+			instruction: StoreScratch{Src: RegX, N: 3},
+			assembler:   "stx M[3]",
+		},
+		{
+			instruction: StoreScratch{Src: 0xffff, N: 3},
+			assembler:   "unknown instruction: bpf.StoreScratch{Src:0xffff, N:3}",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpAdd, Val: 42},
+			assembler:   "add #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpSub, Val: 42},
+			assembler:   "sub #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpMul, Val: 42},
+			assembler:   "mul #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpDiv, Val: 42},
+			assembler:   "div #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpOr, Val: 42},
+			assembler:   "or #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpAnd, Val: 42},
+			assembler:   "and #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpShiftLeft, Val: 42},
+			assembler:   "lsh #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpShiftRight, Val: 42},
+			assembler:   "rsh #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpMod, Val: 42},
+			assembler:   "mod #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: ALUOpXor, Val: 42},
+			assembler:   "xor #42",
+		},
+		{
+			instruction: ALUOpConstant{Op: 0xffff, Val: 42},
+			assembler:   "unknown instruction: bpf.ALUOpConstant{Op:0xffff, Val:0x2a}",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpAdd},
+			assembler:   "add x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpSub},
+			assembler:   "sub x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpMul},
+			assembler:   "mul x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpDiv},
+			assembler:   "div x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpOr},
+			assembler:   "or x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpAnd},
+			assembler:   "and x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpShiftLeft},
+			assembler:   "lsh x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpShiftRight},
+			assembler:   "rsh x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpMod},
+			assembler:   "mod x",
+		},
+		{
+			instruction: ALUOpX{Op: ALUOpXor},
+			assembler:   "xor x",
+		},
+		{
+			instruction: ALUOpX{Op: 0xffff},
+			assembler:   "unknown instruction: bpf.ALUOpX{Op:0xffff}",
+		},
+		{
+			instruction: NegateA{},
+			assembler:   "neg",
+		},
+		{
+			instruction: Jump{Skip: 10},
+			assembler:   "ja 10",
+		},
+		{
+			instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8, SkipFalse: 9},
+			assembler:   "jeq #42,8,9",
+		},
+		{
+			instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8},
+			assembler:   "jeq #42,8",
+		},
+		{
+			instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipFalse: 8},
+			assembler:   "jneq #42,8",
+		},
+		{
+			instruction: JumpIf{Cond: JumpNotEqual, Val: 42, SkipTrue: 8},
+			assembler:   "jneq #42,8",
+		},
+		{
+			instruction: JumpIf{Cond: JumpLessThan, Val: 42, SkipTrue: 7},
+			assembler:   "jlt #42,7",
+		},
+		{
+			instruction: JumpIf{Cond: JumpLessOrEqual, Val: 42, SkipTrue: 6},
+			assembler:   "jle #42,6",
+		},
+		{
+			instruction: JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4, SkipFalse: 5},
+			assembler:   "jgt #42,4,5",
+		},
+		{
+			instruction: JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4},
+			assembler:   "jgt #42,4",
+		},
+		{
+			instruction: JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3, SkipFalse: 4},
+			assembler:   "jge #42,3,4",
+		},
+		{
+			instruction: JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3},
+			assembler:   "jge #42,3",
+		},
+		{
+			instruction: JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
+			assembler:   "jset #42,2,3",
+		},
+		{
+			instruction: JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2},
+			assembler:   "jset #42,2",
+		},
+		{
+			instruction: JumpIf{Cond: JumpBitsNotSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
+			assembler:   "jset #42,3,2",
+		},
+		{
+			instruction: JumpIf{Cond: JumpBitsNotSet, Val: 42, SkipTrue: 2},
+			assembler:   "jset #42,0,2",
+		},
+		{
+			instruction: JumpIf{Cond: 0xffff, Val: 42, SkipTrue: 1, SkipFalse: 2},
+			assembler:   "unknown instruction: bpf.JumpIf{Cond:0xffff, Val:0x2a, SkipTrue:0x1, SkipFalse:0x2}",
+		},
+		{
+			instruction: TAX{},
+			assembler:   "tax",
+		},
+		{
+			instruction: TXA{},
+			assembler:   "txa",
+		},
+		{
+			instruction: RetA{},
+			assembler:   "ret a",
+		},
+		{
+			instruction: RetConstant{Val: 42},
+			assembler:   "ret #42",
+		},
+		// Invalid instruction
+		{
+			instruction: InvalidInstruction{},
+			assembler:   "unknown instruction: bpf.InvalidInstruction{}",
+		},
+	}
+
+	for _, testCase := range testCases {
+		if input, ok := testCase.instruction.(fmt.Stringer); ok {
+			got := input.String()
+			if got != testCase.assembler {
+				t.Errorf("String did not return expected assembler notation, expected: %s, got: %s", testCase.assembler, got)
+			}
+		} else {
+			t.Errorf("Instruction %#v is not a fmt.Stringer", testCase.instruction)
+		}
+	}
+}

+ 10 - 0
vendor/golang.org/x/net/bpf/setter.go

@@ -0,0 +1,10 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+// A Setter is a type which can attach a compiled BPF filter to itself.
+type Setter interface {
+	SetBPF(filter []RawInstruction) error
+}

+ 1 - 0
vendor/golang.org/x/net/bpf/testdata/all_instructions.bpf

@@ -0,0 +1 @@
+50,0 0 0 42,1 0 0 42,96 0 0 3,97 0 0 3,48 0 0 42,40 0 0 42,32 0 0 42,80 0 0 42,72 0 0 42,64 0 0 42,177 0 0 42,128 0 0 0,32 0 0 4294963200,32 0 0 4294963204,32 0 0 4294963256,2 0 0 3,3 0 0 3,4 0 0 42,20 0 0 42,36 0 0 42,52 0 0 42,68 0 0 42,84 0 0 42,100 0 0 42,116 0 0 42,148 0 0 42,164 0 0 42,12 0 0 0,28 0 0 0,44 0 0 0,60 0 0 0,76 0 0 0,92 0 0 0,108 0 0 0,124 0 0 0,156 0 0 0,172 0 0 0,132 0 0 0,5 0 0 10,21 8 9 42,21 0 8 42,53 0 7 42,37 0 6 42,37 4 5 42,53 3 4 42,69 2 3 42,7 0 0 0,135 0 0 0,22 0 0 0,6 0 0 0,

+ 79 - 0
vendor/golang.org/x/net/bpf/testdata/all_instructions.txt

@@ -0,0 +1,79 @@
+# This filter is compiled to all_instructions.bpf by the `bpf_asm`
+# tool, which can be found in the linux kernel source tree under
+# tools/net.
+
+# Load immediate
+ld #42
+ldx #42
+
+# Load scratch
+ld M[3]
+ldx M[3]
+
+# Load absolute
+ldb [42]
+ldh [42]
+ld [42]
+
+# Load indirect
+ldb [x + 42]
+ldh [x + 42]
+ld [x + 42]
+
+# Load IPv4 header length
+ldx 4*([42]&0xf)
+
+# Run extension function
+ld #len
+ld #proto
+ld #type
+ld #rand
+
+# Store scratch
+st M[3]
+stx M[3]
+
+# A <op> constant
+add #42
+sub #42
+mul #42
+div #42
+or #42
+and #42
+lsh #42
+rsh #42
+mod #42
+xor #42
+
+# A <op> X
+add x
+sub x
+mul x
+div x
+or x
+and x
+lsh x
+rsh x
+mod x
+xor x
+
+# !A
+neg
+
+# Jumps
+ja end
+jeq #42,prev,end
+jne #42,end
+jlt #42,end
+jle #42,end
+jgt #42,prev,end
+jge #42,prev,end
+jset #42,prev,end
+
+# Register transfers
+tax
+txa
+
+# Returns
+prev: ret a
+end: ret #42

+ 140 - 0
vendor/golang.org/x/net/bpf/vm.go

@@ -0,0 +1,140 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+import (
+	"errors"
+	"fmt"
+)
+
+// A VM is an emulated BPF virtual machine.
+type VM struct {
+	filter []Instruction
+}
+
+// NewVM returns a new VM using the input BPF program.
+func NewVM(filter []Instruction) (*VM, error) {
+	if len(filter) == 0 {
+		return nil, errors.New("one or more Instructions must be specified")
+	}
+
+	for i, ins := range filter {
+		check := len(filter) - (i + 1)
+		switch ins := ins.(type) {
+		// Check for out-of-bounds jumps in instructions
+		case Jump:
+			if check <= int(ins.Skip) {
+				return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
+			}
+		case JumpIf:
+			if check <= int(ins.SkipTrue) {
+				return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
+			}
+			if check <= int(ins.SkipFalse) {
+				return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
+			}
+		// Check for division or modulus by zero
+		case ALUOpConstant:
+			if ins.Val != 0 {
+				break
+			}
+
+			switch ins.Op {
+			case ALUOpDiv, ALUOpMod:
+				return nil, errors.New("cannot divide by zero using ALUOpConstant")
+			}
+		// Check for unknown extensions
+		case LoadExtension:
+			switch ins.Num {
+			case ExtLen:
+			default:
+				return nil, fmt.Errorf("extension %d not implemented", ins.Num)
+			}
+		}
+	}
+
+	// Make sure last instruction is a return instruction
+	switch filter[len(filter)-1].(type) {
+	case RetA, RetConstant:
+	default:
+		return nil, errors.New("BPF program must end with RetA or RetConstant")
+	}
+
+	// Though our VM works using disassembled instructions, we
+	// attempt to assemble the input filter anyway to ensure it is compatible
+	// with an operating system VM.
+	_, err := Assemble(filter)
+
+	return &VM{
+		filter: filter,
+	}, err
+}
+
+// Run runs the VM's BPF program against the input bytes.
+// Run returns the number of bytes accepted by the BPF program, and any errors
+// which occurred while processing the program.
+func (v *VM) Run(in []byte) (int, error) {
+	var (
+		// Registers of the virtual machine
+		regA       uint32
+		regX       uint32
+		regScratch [16]uint32
+
+		// OK is true if the program should continue processing the next
+		// instruction, or false if not, causing the loop to break
+		ok = true
+	)
+
+	// TODO(mdlayher): implement:
+	// - NegateA:
+	//   - would require a change from uint32 registers to int32
+	//     registers
+
+	// TODO(mdlayher): add interop tests that check signedness of ALU
+	// operations against kernel implementation, and make sure Go
+	// implementation matches behavior
+
+	for i := 0; i < len(v.filter) && ok; i++ {
+		ins := v.filter[i]
+
+		switch ins := ins.(type) {
+		case ALUOpConstant:
+			regA = aluOpConstant(ins, regA)
+		case ALUOpX:
+			regA, ok = aluOpX(ins, regA, regX)
+		case Jump:
+			i += int(ins.Skip)
+		case JumpIf:
+			jump := jumpIf(ins, regA)
+			i += jump
+		case LoadAbsolute:
+			regA, ok = loadAbsolute(ins, in)
+		case LoadConstant:
+			regA, regX = loadConstant(ins, regA, regX)
+		case LoadExtension:
+			regA = loadExtension(ins, in)
+		case LoadIndirect:
+			regA, ok = loadIndirect(ins, in, regX)
+		case LoadMemShift:
+			regX, ok = loadMemShift(ins, in)
+		case LoadScratch:
+			regA, regX = loadScratch(ins, regScratch, regA, regX)
+		case RetA:
+			return int(regA), nil
+		case RetConstant:
+			return int(ins.Val), nil
+		case StoreScratch:
+			regScratch = storeScratch(ins, regScratch, regA, regX)
+		case TAX:
+			regX = regA
+		case TXA:
+			regA = regX
+		default:
+			return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
+		}
+	}
+
+	return 0, nil
+}

+ 512 - 0
vendor/golang.org/x/net/bpf/vm_aluop_test.go

@@ -0,0 +1,512 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+func TestVMALUOpAdd(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpAdd,
+			Val: 3,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		8, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 3, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpSub(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.TAX{},
+		bpf.ALUOpX{
+			Op: bpf.ALUOpSub,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpMul(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpMul,
+			Val: 2,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		6, 2, 3, 4,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpDiv(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpDiv,
+			Val: 2,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		20, 2, 3, 4,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpDivByZeroALUOpConstant(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpDiv,
+			Val: 0,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "cannot divide by zero using ALUOpConstant" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMALUOpDivByZeroALUOpX(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		// Load byte 0 into X
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.TAX{},
+		// Load byte 1 into A
+		bpf.LoadAbsolute{
+			Off:  9,
+			Size: 1,
+		},
+		// Attempt to perform 1/0
+		bpf.ALUOpX{
+			Op: bpf.ALUOpDiv,
+		},
+		// Return 4 bytes if program does not terminate
+		bpf.LoadConstant{
+			Val: 12,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 3, 4,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpOr(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 2,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpOr,
+			Val: 0x01,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x00, 0x10, 0x03, 0x04,
+		0x05, 0x06, 0x07, 0x08,
+		0x09, 0xff,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 9, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpAnd(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 2,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpAnd,
+			Val: 0x0019,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0xaa, 0x09,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpShiftLeft(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpShiftLeft,
+			Val: 0x01,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      0x02,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x01, 0xaa,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpShiftRight(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpShiftRight,
+			Val: 0x01,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      0x04,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x08, 0xff, 0xff,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpMod(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpMod,
+			Val: 20,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		30, 0, 0,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpModByZeroALUOpConstant(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpMod,
+			Val: 0,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "cannot divide by zero using ALUOpConstant" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMALUOpModByZeroALUOpX(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		// Load byte 0 into X
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.TAX{},
+		// Load byte 1 into A
+		bpf.LoadAbsolute{
+			Off:  9,
+			Size: 1,
+		},
+		// Attempt to perform 1%0
+		bpf.ALUOpX{
+			Op: bpf.ALUOpMod,
+		},
+		// Return 4 bytes if program does not terminate
+		bpf.LoadConstant{
+			Val: 12,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 3, 4,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpXor(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpXor,
+			Val: 0x0a,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      0x01,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x0b, 0x00, 0x00, 0x00,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMALUOpUnknown(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.ALUOpConstant{
+			Op:  bpf.ALUOpAdd,
+			Val: 1,
+		},
+		// Verify that an unknown operation is a no-op
+		bpf.ALUOpConstant{
+			Op: 100,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      0x02,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}

+ 192 - 0
vendor/golang.org/x/net/bpf/vm_bpf_test.go

@@ -0,0 +1,192 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"net"
+	"runtime"
+	"testing"
+	"time"
+
+	"golang.org/x/net/bpf"
+	"golang.org/x/net/ipv4"
+)
+
+// A virtualMachine is a BPF virtual machine which can process an
+// input packet against a BPF program and render a verdict.
+type virtualMachine interface {
+	Run(in []byte) (int, error)
+}
+
+// canUseOSVM indicates if the OS BPF VM is available on this platform.
+func canUseOSVM() bool {
+	// OS BPF VM can only be used on platforms where x/net/ipv4 supports
+	// attaching a BPF program to a socket.
+	switch runtime.GOOS {
+	case "linux":
+		return true
+	}
+
+	return false
+}
+
+// All BPF tests against both the Go VM and OS VM are assumed to
+// be used with a UDP socket. As a result, the entire contents
+// of a UDP datagram is sent through the BPF program, but only
+// the body after the UDP header will ever be returned in output.
+
+// testVM sets up a Go BPF VM, and if available, a native OS BPF VM
+// for integration testing.
+func testVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func(), error) {
+	goVM, err := bpf.NewVM(filter)
+	if err != nil {
+		// Some tests expect an error, so this error must be returned
+		// instead of fatally exiting the test
+		return nil, nil, err
+	}
+
+	mvm := &multiVirtualMachine{
+		goVM: goVM,
+
+		t: t,
+	}
+
+	// If available, add the OS VM for tests which verify that both the Go
+	// VM and OS VM have exactly the same output for the same input program
+	// and packet.
+	done := func() {}
+	if canUseOSVM() {
+		osVM, osVMDone := testOSVM(t, filter)
+		done = func() { osVMDone() }
+		mvm.osVM = osVM
+	}
+
+	return mvm, done, nil
+}
+
+// udpHeaderLen is the length of a UDP header.
+const udpHeaderLen = 8
+
+// A multiVirtualMachine is a virtualMachine which can call out to both the Go VM
+// and the native OS VM, if the OS VM is available.
+type multiVirtualMachine struct {
+	goVM virtualMachine
+	osVM virtualMachine
+
+	t *testing.T
+}
+
+func (mvm *multiVirtualMachine) Run(in []byte) (int, error) {
+	if len(in) < udpHeaderLen {
+		mvm.t.Fatalf("input must be at least length of UDP header (%d), got: %d",
+			udpHeaderLen, len(in))
+	}
+
+	// All tests have a UDP header as part of input, because the OS VM
+	// packets always will. For the Go VM, this output is trimmed before
+	// being sent back to tests.
+	goOut, goErr := mvm.goVM.Run(in)
+	if goOut >= udpHeaderLen {
+		goOut -= udpHeaderLen
+	}
+
+	// If Go output is larger than the size of the packet, packet filtering
+	// interop tests must trim the output bytes to the length of the packet.
+	// The BPF VM should not do this on its own, as other uses of it do
+	// not trim the output byte count.
+	trim := len(in) - udpHeaderLen
+	if goOut > trim {
+		goOut = trim
+	}
+
+	// When the OS VM is not available, process using the Go VM alone
+	if mvm.osVM == nil {
+		return goOut, goErr
+	}
+
+	// The OS VM will apply its own UDP header, so remove the pseudo header
+	// that the Go VM needs.
+	osOut, err := mvm.osVM.Run(in[udpHeaderLen:])
+	if err != nil {
+		mvm.t.Fatalf("error while running OS VM: %v", err)
+	}
+
+	// Verify both VMs return same number of bytes
+	var mismatch bool
+	if goOut != osOut {
+		mismatch = true
+		mvm.t.Logf("output byte count does not match:\n- go: %v\n- os: %v", goOut, osOut)
+	}
+
+	if mismatch {
+		mvm.t.Fatal("Go BPF and OS BPF packet outputs do not match")
+	}
+
+	return goOut, goErr
+}
+
+// An osVirtualMachine is a virtualMachine which uses the OS's BPF VM for
+// processing BPF programs.
+type osVirtualMachine struct {
+	l net.PacketConn
+	s net.Conn
+}
+
+// testOSVM creates a virtualMachine which uses the OS's BPF VM by injecting
+// packets into a UDP listener with a BPF program attached to it.
+func testOSVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func()) {
+	l, err := net.ListenPacket("udp4", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("failed to open OS VM UDP listener: %v", err)
+	}
+
+	prog, err := bpf.Assemble(filter)
+	if err != nil {
+		t.Fatalf("failed to compile BPF program: %v", err)
+	}
+
+	p := ipv4.NewPacketConn(l)
+	if err = p.SetBPF(prog); err != nil {
+		t.Fatalf("failed to attach BPF program to listener: %v", err)
+	}
+
+	s, err := net.Dial("udp4", l.LocalAddr().String())
+	if err != nil {
+		t.Fatalf("failed to dial connection to listener: %v", err)
+	}
+
+	done := func() {
+		_ = s.Close()
+		_ = l.Close()
+	}
+
+	return &osVirtualMachine{
+		l: l,
+		s: s,
+	}, done
+}
+
+// Run sends the input bytes into the OS's BPF VM and returns its verdict.
+func (vm *osVirtualMachine) Run(in []byte) (int, error) {
+	go func() {
+		_, _ = vm.s.Write(in)
+	}()
+
+	vm.l.SetDeadline(time.Now().Add(50 * time.Millisecond))
+
+	var b [512]byte
+	n, _, err := vm.l.ReadFrom(b[:])
+	if err != nil {
+		// A timeout indicates that BPF filtered out the packet, and thus,
+		// no input should be returned.
+		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
+			return n, nil
+		}
+
+		return n, err
+	}
+
+	return n, nil
+}

+ 49 - 0
vendor/golang.org/x/net/bpf/vm_extension_test.go

@@ -0,0 +1,49 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+func TestVMLoadExtensionNotImplemented(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadExtension{
+			Num: 100,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "extension 100 not implemented" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMLoadExtensionExtLen(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadExtension{
+			Num: bpf.ExtLen,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}

+ 174 - 0
vendor/golang.org/x/net/bpf/vm_instructions.go

@@ -0,0 +1,174 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf
+
+import (
+	"encoding/binary"
+	"fmt"
+)
+
+func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
+	return aluOpCommon(ins.Op, regA, ins.Val)
+}
+
+func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
+	// Guard against division or modulus by zero by terminating
+	// the program, as the OS BPF VM does
+	if regX == 0 {
+		switch ins.Op {
+		case ALUOpDiv, ALUOpMod:
+			return 0, false
+		}
+	}
+
+	return aluOpCommon(ins.Op, regA, regX), true
+}
+
+func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
+	switch op {
+	case ALUOpAdd:
+		return regA + value
+	case ALUOpSub:
+		return regA - value
+	case ALUOpMul:
+		return regA * value
+	case ALUOpDiv:
+		// Division by zero not permitted by NewVM and aluOpX checks
+		return regA / value
+	case ALUOpOr:
+		return regA | value
+	case ALUOpAnd:
+		return regA & value
+	case ALUOpShiftLeft:
+		return regA << value
+	case ALUOpShiftRight:
+		return regA >> value
+	case ALUOpMod:
+		// Modulus by zero not permitted by NewVM and aluOpX checks
+		return regA % value
+	case ALUOpXor:
+		return regA ^ value
+	default:
+		return regA
+	}
+}
+
+func jumpIf(ins JumpIf, value uint32) int {
+	var ok bool
+	inV := uint32(ins.Val)
+
+	switch ins.Cond {
+	case JumpEqual:
+		ok = value == inV
+	case JumpNotEqual:
+		ok = value != inV
+	case JumpGreaterThan:
+		ok = value > inV
+	case JumpLessThan:
+		ok = value < inV
+	case JumpGreaterOrEqual:
+		ok = value >= inV
+	case JumpLessOrEqual:
+		ok = value <= inV
+	case JumpBitsSet:
+		ok = (value & inV) != 0
+	case JumpBitsNotSet:
+		ok = (value & inV) == 0
+	}
+
+	if ok {
+		return int(ins.SkipTrue)
+	}
+
+	return int(ins.SkipFalse)
+}
+
+func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
+	offset := int(ins.Off)
+	size := int(ins.Size)
+
+	return loadCommon(in, offset, size)
+}
+
+func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
+	switch ins.Dst {
+	case RegA:
+		regA = ins.Val
+	case RegX:
+		regX = ins.Val
+	}
+
+	return regA, regX
+}
+
+func loadExtension(ins LoadExtension, in []byte) uint32 {
+	switch ins.Num {
+	case ExtLen:
+		return uint32(len(in))
+	default:
+		panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
+	}
+}
+
+func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
+	offset := int(ins.Off) + int(regX)
+	size := int(ins.Size)
+
+	return loadCommon(in, offset, size)
+}
+
+func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
+	offset := int(ins.Off)
+
+	if !inBounds(len(in), offset, 0) {
+		return 0, false
+	}
+
+	// Mask off high 4 bits and multiply low 4 bits by 4
+	return uint32(in[offset]&0x0f) * 4, true
+}
+
+func inBounds(inLen int, offset int, size int) bool {
+	return offset+size <= inLen
+}
+
+func loadCommon(in []byte, offset int, size int) (uint32, bool) {
+	if !inBounds(len(in), offset, size) {
+		return 0, false
+	}
+
+	switch size {
+	case 1:
+		return uint32(in[offset]), true
+	case 2:
+		return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
+	case 4:
+		return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
+	default:
+		panic(fmt.Sprintf("invalid load size: %d", size))
+	}
+}
+
+func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
+	switch ins.Dst {
+	case RegA:
+		regA = regScratch[ins.N]
+	case RegX:
+		regX = regScratch[ins.N]
+	}
+
+	return regA, regX
+}
+
+func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
+	switch ins.Src {
+	case RegA:
+		regScratch[ins.N] = regA
+	case RegX:
+		regScratch[ins.N] = regX
+	}
+
+	return regScratch
+}

+ 380 - 0
vendor/golang.org/x/net/bpf/vm_jump_test.go

@@ -0,0 +1,380 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+func TestVMJumpOne(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.Jump{
+			Skip: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpOutOfProgram(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.Jump{
+			Skip: 1,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "cannot jump 1 instructions; jumping past program bounds" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMJumpIfTrueOutOfProgram(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			SkipTrue: 2,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "cannot jump 2 instructions in true case; jumping past program bounds" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMJumpIfFalseOutOfProgram(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.JumpIf{
+			Cond:      bpf.JumpEqual,
+			SkipFalse: 3,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "cannot jump 3 instructions in false case; jumping past program bounds" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMJumpIfEqual(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      1,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfNotEqual(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.JumpIf{
+			Cond:      bpf.JumpNotEqual,
+			Val:       1,
+			SkipFalse: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfGreaterThan(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 4,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpGreaterThan,
+			Val:      0x00010202,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 12,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfLessThan(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 4,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpLessThan,
+			Val:      0xff010203,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 12,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfGreaterOrEqual(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 4,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpGreaterOrEqual,
+			Val:      0x00010203,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 12,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfLessOrEqual(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 4,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpLessOrEqual,
+			Val:      0xff010203,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 12,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfBitsSet(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 2,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpBitsSet,
+			Val:      0x1122,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 10,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x01, 0x02,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMJumpIfBitsNotSet(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 2,
+		},
+		bpf.JumpIf{
+			Cond:     bpf.JumpBitsNotSet,
+			Val:      0x1221,
+			SkipTrue: 1,
+		},
+		bpf.RetConstant{
+			Val: 0,
+		},
+		bpf.RetConstant{
+			Val: 10,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x01, 0x02,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}

+ 246 - 0
vendor/golang.org/x/net/bpf/vm_load_test.go

@@ -0,0 +1,246 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"net"
+	"testing"
+
+	"golang.org/x/net/bpf"
+	"golang.org/x/net/ipv4"
+)
+
+func TestVMLoadAbsoluteOffsetOutOfBounds(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  100,
+			Size: 2,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMLoadAbsoluteOffsetPlusSizeOutOfBounds(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 2,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMLoadAbsoluteBadInstructionSize(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Size: 5,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid load byte length 0" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMLoadConstantOK(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadConstant{
+			Dst: bpf.RegX,
+			Val: 9,
+		},
+		bpf.TXA{},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMLoadIndirectOutOfBounds(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadIndirect{
+			Off:  100,
+			Size: 1,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMLoadMemShiftOutOfBounds(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadMemShift{
+			Off: 100,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+const (
+	dhcp4Port = 53
+)
+
+func TestVMLoadMemShiftLoadIndirectNoResult(t *testing.T) {
+	vm, in, done := testDHCPv4(t)
+	defer done()
+
+	// Append mostly empty UDP header with incorrect DHCPv4 port
+	in = append(in, []byte{
+		0, 0,
+		0, dhcp4Port + 1,
+		0, 0,
+		0, 0,
+	}...)
+
+	out, err := vm.Run(in)
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 0, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMLoadMemShiftLoadIndirectOK(t *testing.T) {
+	vm, in, done := testDHCPv4(t)
+	defer done()
+
+	// Append mostly empty UDP header with correct DHCPv4 port
+	in = append(in, []byte{
+		0, 0,
+		0, dhcp4Port,
+		0, 0,
+		0, 0,
+	}...)
+
+	out, err := vm.Run(in)
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := len(in)-8, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func testDHCPv4(t *testing.T) (virtualMachine, []byte, func()) {
+	// DHCPv4 test data courtesy of David Anderson:
+	// https://github.com/google/netboot/blob/master/dhcp4/conn_linux.go#L59-L70
+	vm, done, err := testVM(t, []bpf.Instruction{
+		// Load IPv4 packet length
+		bpf.LoadMemShift{Off: 8},
+		// Get UDP dport
+		bpf.LoadIndirect{Off: 8 + 2, Size: 2},
+		// Correct dport?
+		bpf.JumpIf{Cond: bpf.JumpEqual, Val: dhcp4Port, SkipFalse: 1},
+		// Accept
+		bpf.RetConstant{Val: 1500},
+		// Ignore
+		bpf.RetConstant{Val: 0},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+
+	// Minimal requirements to make a valid IPv4 header
+	h := &ipv4.Header{
+		Len: ipv4.HeaderLen,
+		Src: net.IPv4(192, 168, 1, 1),
+		Dst: net.IPv4(192, 168, 1, 2),
+	}
+	hb, err := h.Marshal()
+	if err != nil {
+		t.Fatalf("failed to marshal IPv4 header: %v", err)
+	}
+
+	hb = append([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+	}, hb...)
+
+	return vm, hb, done
+}

+ 115 - 0
vendor/golang.org/x/net/bpf/vm_ret_test.go

@@ -0,0 +1,115 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+func TestVMRetA(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		9,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMRetALargerThanInput(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 2,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 255,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMRetConstant(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.RetConstant{
+			Val: 9,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 1, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMRetConstantLargerThanInput(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.RetConstant{
+			Val: 16,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}

+ 247 - 0
vendor/golang.org/x/net/bpf/vm_scratch_test.go

@@ -0,0 +1,247 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+func TestVMStoreScratchInvalidScratchRegisterTooSmall(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.StoreScratch{
+			Src: bpf.RegA,
+			N:   -1,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid scratch slot -1" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMStoreScratchInvalidScratchRegisterTooLarge(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.StoreScratch{
+			Src: bpf.RegA,
+			N:   16,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid scratch slot 16" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMStoreScratchUnknownSourceRegister(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.StoreScratch{
+			Src: 100,
+			N:   0,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid source register 100" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMLoadScratchInvalidScratchRegisterTooSmall(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadScratch{
+			Dst: bpf.RegX,
+			N:   -1,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid scratch slot -1" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMLoadScratchInvalidScratchRegisterTooLarge(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadScratch{
+			Dst: bpf.RegX,
+			N:   16,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid scratch slot 16" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMLoadScratchUnknownDestinationRegister(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadScratch{
+			Dst: 100,
+			N:   0,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "assembling instruction 1: invalid target register 100" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMStoreScratchLoadScratchOneValue(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		// Load byte 255
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		// Copy to X and store in scratch[0]
+		bpf.TAX{},
+		bpf.StoreScratch{
+			Src: bpf.RegX,
+			N:   0,
+		},
+		// Load byte 1
+		bpf.LoadAbsolute{
+			Off:  9,
+			Size: 1,
+		},
+		// Overwrite 1 with 255 from scratch[0]
+		bpf.LoadScratch{
+			Dst: bpf.RegA,
+			N:   0,
+		},
+		// Return 255
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		255, 1, 2,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 3, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
+
+func TestVMStoreScratchLoadScratchMultipleValues(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		// Load byte 10
+		bpf.LoadAbsolute{
+			Off:  8,
+			Size: 1,
+		},
+		// Store in scratch[0]
+		bpf.StoreScratch{
+			Src: bpf.RegA,
+			N:   0,
+		},
+		// Load byte 20
+		bpf.LoadAbsolute{
+			Off:  9,
+			Size: 1,
+		},
+		// Store in scratch[1]
+		bpf.StoreScratch{
+			Src: bpf.RegA,
+			N:   1,
+		},
+		// Load byte 30
+		bpf.LoadAbsolute{
+			Off:  10,
+			Size: 1,
+		},
+		// Store in scratch[2]
+		bpf.StoreScratch{
+			Src: bpf.RegA,
+			N:   2,
+		},
+		// Load byte 1
+		bpf.LoadAbsolute{
+			Off:  11,
+			Size: 1,
+		},
+		// Store in scratch[3]
+		bpf.StoreScratch{
+			Src: bpf.RegA,
+			N:   3,
+		},
+		// Load in byte 10 to X
+		bpf.LoadScratch{
+			Dst: bpf.RegX,
+			N:   0,
+		},
+		// Copy X -> A
+		bpf.TXA{},
+		// Verify value is 10
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      10,
+			SkipTrue: 1,
+		},
+		// Fail test if incorrect
+		bpf.RetConstant{
+			Val: 0,
+		},
+		// Load in byte 20 to A
+		bpf.LoadScratch{
+			Dst: bpf.RegA,
+			N:   1,
+		},
+		// Verify value is 20
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      20,
+			SkipTrue: 1,
+		},
+		// Fail test if incorrect
+		bpf.RetConstant{
+			Val: 0,
+		},
+		// Load in byte 30 to A
+		bpf.LoadScratch{
+			Dst: bpf.RegA,
+			N:   2,
+		},
+		// Verify value is 30
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      30,
+			SkipTrue: 1,
+		},
+		// Fail test if incorrect
+		bpf.RetConstant{
+			Val: 0,
+		},
+		// Return first two bytes on success
+		bpf.RetConstant{
+			Val: 10,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		10, 20, 30, 1,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 2, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}

+ 144 - 0
vendor/golang.org/x/net/bpf/vm_test.go

@@ -0,0 +1,144 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"fmt"
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+var _ bpf.Instruction = unknown{}
+
+type unknown struct{}
+
+func (unknown) Assemble() (bpf.RawInstruction, error) {
+	return bpf.RawInstruction{}, nil
+}
+
+func TestVMUnknownInstruction(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadConstant{
+			Dst: bpf.RegA,
+			Val: 100,
+		},
+		// Should terminate the program with an error immediately
+		unknown{},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+	defer done()
+
+	_, err = vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0x00, 0x00,
+	})
+	if errStr(err) != "unknown Instruction at index 1: bpf_test.unknown" {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+}
+
+func TestVMNoReturnInstruction(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadConstant{
+			Dst: bpf.RegA,
+			Val: 1,
+		},
+	})
+	if errStr(err) != "BPF program must end with RetA or RetConstant" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMNoInputInstructions(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{})
+	if errStr(err) != "one or more Instructions must be specified" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+// ExampleNewVM demonstrates usage of a VM, using an Ethernet frame
+// as input and checking its EtherType to determine if it should be accepted.
+func ExampleNewVM() {
+	// Offset | Length | Comment
+	// -------------------------
+	//   00   |   06   | Ethernet destination MAC address
+	//   06   |   06   | Ethernet source MAC address
+	//   12   |   02   | Ethernet EtherType
+	const (
+		etOff = 12
+		etLen = 2
+
+		etARP = 0x0806
+	)
+
+	// Set up a VM to filter traffic based on if its EtherType
+	// matches the ARP EtherType.
+	vm, err := bpf.NewVM([]bpf.Instruction{
+		// Load EtherType value from Ethernet header
+		bpf.LoadAbsolute{
+			Off:  etOff,
+			Size: etLen,
+		},
+		// If EtherType is equal to the ARP EtherType, jump to allow
+		// packet to be accepted
+		bpf.JumpIf{
+			Cond:     bpf.JumpEqual,
+			Val:      etARP,
+			SkipTrue: 1,
+		},
+		// EtherType does not match the ARP EtherType
+		bpf.RetConstant{
+			Val: 0,
+		},
+		// EtherType matches the ARP EtherType, accept up to 1500
+		// bytes of packet
+		bpf.RetConstant{
+			Val: 1500,
+		},
+	})
+	if err != nil {
+		panic(fmt.Sprintf("failed to load BPF program: %v", err))
+	}
+
+	// Create an Ethernet frame with the ARP EtherType for testing
+	frame := []byte{
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+		0x08, 0x06,
+		// Payload omitted for brevity
+	}
+
+	// Run our VM's BPF program using the Ethernet frame as input
+	out, err := vm.Run(frame)
+	if err != nil {
+		panic(fmt.Sprintf("failed to accept Ethernet frame: %v", err))
+	}
+
+	// BPF VM can return a byte count greater than the number of input
+	// bytes, so trim the output to match the input byte length
+	if out > len(frame) {
+		out = len(frame)
+	}
+
+	fmt.Printf("out: %d bytes", out)
+
+	// Output:
+	// out: 14 bytes
+}
+
+// errStr returns the string representation of an error, or
+// "<nil>" if it is nil.
+func errStr(err error) string {
+	if err == nil {
+		return "<nil>"
+	}
+
+	return err.Error()
+}

+ 1 - 0
vendor/golang.org/x/net/codereview.cfg

@@ -0,0 +1 @@
+issuerepo: golang/go

+ 54 - 0
vendor/golang.org/x/net/context/context.go

@@ -0,0 +1,54 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package context defines the Context type, which carries deadlines,
+// cancelation signals, and other request-scoped values across API boundaries
+// and between processes.
+//
+// Incoming requests to a server should create a Context, and outgoing calls to
+// servers should accept a Context. The chain of function calls between must
+// propagate the Context, optionally replacing it with a modified copy created
+// using WithDeadline, WithTimeout, WithCancel, or WithValue.
+//
+// Programs that use Contexts should follow these rules to keep interfaces
+// consistent across packages and enable static analysis tools to check context
+// propagation:
+//
+// Do not store Contexts inside a struct type; instead, pass a Context
+// explicitly to each function that needs it. The Context should be the first
+// parameter, typically named ctx:
+//
+// 	func DoSomething(ctx context.Context, arg Arg) error {
+// 		// ... use ctx ...
+// 	}
+//
+// Do not pass a nil Context, even if a function permits it. Pass context.TODO
+// if you are unsure about which Context to use.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The same Context may be passed to functions running in different goroutines;
+// Contexts are safe for simultaneous use by multiple goroutines.
+//
+// See http://blog.golang.org/context for example code for a server that uses
+// Contexts.
+package context // import "golang.org/x/net/context"
+
+// Background returns a non-nil, empty Context. It is never canceled, has no
+// values, and has no deadline. It is typically used by the main function,
+// initialization, and tests, and as the top-level Context for incoming
+// requests.
+func Background() Context {
+	return background
+}
+
+// TODO returns a non-nil, empty Context. Code should use context.TODO when
+// it's unclear which Context to use or it is not yet available (because the
+// surrounding function has not yet been extended to accept a Context
+// parameter).  TODO is recognized by static analysis tools that determine
+// whether Contexts are propagated correctly in a program.
+func TODO() Context {
+	return todo
+}

+ 583 - 0
vendor/golang.org/x/net/context/context_test.go

@@ -0,0 +1,583 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7
+
+package context
+
+import (
+	"fmt"
+	"math/rand"
+	"runtime"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+)
+
+// otherContext is a Context that's not one of the types defined in context.go.
+// This lets us test code paths that differ based on the underlying type of the
+// Context.
+type otherContext struct {
+	Context
+}
+
+func TestBackground(t *testing.T) {
+	c := Background()
+	if c == nil {
+		t.Fatalf("Background returned nil")
+	}
+	select {
+	case x := <-c.Done():
+		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+	default:
+	}
+	if got, want := fmt.Sprint(c), "context.Background"; got != want {
+		t.Errorf("Background().String() = %q want %q", got, want)
+	}
+}
+
+func TestTODO(t *testing.T) {
+	c := TODO()
+	if c == nil {
+		t.Fatalf("TODO returned nil")
+	}
+	select {
+	case x := <-c.Done():
+		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+	default:
+	}
+	if got, want := fmt.Sprint(c), "context.TODO"; got != want {
+		t.Errorf("TODO().String() = %q want %q", got, want)
+	}
+}
+
+func TestWithCancel(t *testing.T) {
+	c1, cancel := WithCancel(Background())
+
+	if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
+		t.Errorf("c1.String() = %q want %q", got, want)
+	}
+
+	o := otherContext{c1}
+	c2, _ := WithCancel(o)
+	contexts := []Context{c1, o, c2}
+
+	for i, c := range contexts {
+		if d := c.Done(); d == nil {
+			t.Errorf("c[%d].Done() == %v want non-nil", i, d)
+		}
+		if e := c.Err(); e != nil {
+			t.Errorf("c[%d].Err() == %v want nil", i, e)
+		}
+
+		select {
+		case x := <-c.Done():
+			t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+		default:
+		}
+	}
+
+	cancel()
+	time.Sleep(100 * time.Millisecond) // let cancelation propagate
+
+	for i, c := range contexts {
+		select {
+		case <-c.Done():
+		default:
+			t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
+		}
+		if e := c.Err(); e != Canceled {
+			t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
+		}
+	}
+}
+
+func TestParentFinishesChild(t *testing.T) {
+	// Context tree:
+	// parent -> cancelChild
+	// parent -> valueChild -> timerChild
+	parent, cancel := WithCancel(Background())
+	cancelChild, stop := WithCancel(parent)
+	defer stop()
+	valueChild := WithValue(parent, "key", "value")
+	timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
+	defer stop()
+
+	select {
+	case x := <-parent.Done():
+		t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+	case x := <-cancelChild.Done():
+		t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
+	case x := <-timerChild.Done():
+		t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
+	case x := <-valueChild.Done():
+		t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
+	default:
+	}
+
+	// The parent's children should contain the two cancelable children.
+	pc := parent.(*cancelCtx)
+	cc := cancelChild.(*cancelCtx)
+	tc := timerChild.(*timerCtx)
+	pc.mu.Lock()
+	if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
+		t.Errorf("bad linkage: pc.children = %v, want %v and %v",
+			pc.children, cc, tc)
+	}
+	pc.mu.Unlock()
+
+	if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
+		t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
+	}
+	if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
+		t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
+	}
+
+	cancel()
+
+	pc.mu.Lock()
+	if len(pc.children) != 0 {
+		t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
+	}
+	pc.mu.Unlock()
+
+	// parent and children should all be finished.
+	check := func(ctx Context, name string) {
+		select {
+		case <-ctx.Done():
+		default:
+			t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
+		}
+		if e := ctx.Err(); e != Canceled {
+			t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
+		}
+	}
+	check(parent, "parent")
+	check(cancelChild, "cancelChild")
+	check(valueChild, "valueChild")
+	check(timerChild, "timerChild")
+
+	// WithCancel should return a canceled context on a canceled parent.
+	precanceledChild := WithValue(parent, "key", "value")
+	select {
+	case <-precanceledChild.Done():
+	default:
+		t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
+	}
+	if e := precanceledChild.Err(); e != Canceled {
+		t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
+	}
+}
+
+func TestChildFinishesFirst(t *testing.T) {
+	cancelable, stop := WithCancel(Background())
+	defer stop()
+	for _, parent := range []Context{Background(), cancelable} {
+		child, cancel := WithCancel(parent)
+
+		select {
+		case x := <-parent.Done():
+			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+		case x := <-child.Done():
+			t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
+		default:
+		}
+
+		cc := child.(*cancelCtx)
+		pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
+		if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
+			t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
+		}
+
+		if pcok {
+			pc.mu.Lock()
+			if len(pc.children) != 1 || !pc.children[cc] {
+				t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
+			}
+			pc.mu.Unlock()
+		}
+
+		cancel()
+
+		if pcok {
+			pc.mu.Lock()
+			if len(pc.children) != 0 {
+				t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
+			}
+			pc.mu.Unlock()
+		}
+
+		// child should be finished.
+		select {
+		case <-child.Done():
+		default:
+			t.Errorf("<-child.Done() blocked, but shouldn't have")
+		}
+		if e := child.Err(); e != Canceled {
+			t.Errorf("child.Err() == %v want %v", e, Canceled)
+		}
+
+		// parent should not be finished.
+		select {
+		case x := <-parent.Done():
+			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+		default:
+		}
+		if e := parent.Err(); e != nil {
+			t.Errorf("parent.Err() == %v want nil", e)
+		}
+	}
+}
+
+func testDeadline(c Context, wait time.Duration, t *testing.T) {
+	select {
+	case <-time.After(wait):
+		t.Fatalf("context should have timed out")
+	case <-c.Done():
+	}
+	if e := c.Err(); e != DeadlineExceeded {
+		t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded)
+	}
+}
+
+func TestDeadline(t *testing.T) {
+	t.Parallel()
+	const timeUnit = 500 * time.Millisecond
+	c, _ := WithDeadline(Background(), time.Now().Add(1*timeUnit))
+	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+		t.Errorf("c.String() = %q want prefix %q", got, prefix)
+	}
+	testDeadline(c, 2*timeUnit, t)
+
+	c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit))
+	o := otherContext{c}
+	testDeadline(o, 2*timeUnit, t)
+
+	c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit))
+	o = otherContext{c}
+	c, _ = WithDeadline(o, time.Now().Add(3*timeUnit))
+	testDeadline(c, 2*timeUnit, t)
+}
+
+func TestTimeout(t *testing.T) {
+	t.Parallel()
+	const timeUnit = 500 * time.Millisecond
+	c, _ := WithTimeout(Background(), 1*timeUnit)
+	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+		t.Errorf("c.String() = %q want prefix %q", got, prefix)
+	}
+	testDeadline(c, 2*timeUnit, t)
+
+	c, _ = WithTimeout(Background(), 1*timeUnit)
+	o := otherContext{c}
+	testDeadline(o, 2*timeUnit, t)
+
+	c, _ = WithTimeout(Background(), 1*timeUnit)
+	o = otherContext{c}
+	c, _ = WithTimeout(o, 3*timeUnit)
+	testDeadline(c, 2*timeUnit, t)
+}
+
+func TestCanceledTimeout(t *testing.T) {
+	t.Parallel()
+	const timeUnit = 500 * time.Millisecond
+	c, _ := WithTimeout(Background(), 2*timeUnit)
+	o := otherContext{c}
+	c, cancel := WithTimeout(o, 4*timeUnit)
+	cancel()
+	time.Sleep(1 * timeUnit) // let cancelation propagate
+	select {
+	case <-c.Done():
+	default:
+		t.Errorf("<-c.Done() blocked, but shouldn't have")
+	}
+	if e := c.Err(); e != Canceled {
+		t.Errorf("c.Err() == %v want %v", e, Canceled)
+	}
+}
+
+type key1 int
+type key2 int
+
+var k1 = key1(1)
+var k2 = key2(1) // same int as k1, different type
+var k3 = key2(3) // same type as k2, different int
+
+func TestValues(t *testing.T) {
+	check := func(c Context, nm, v1, v2, v3 string) {
+		if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
+			t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
+		}
+		if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
+			t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
+		}
+		if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
+			t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
+		}
+	}
+
+	c0 := Background()
+	check(c0, "c0", "", "", "")
+
+	c1 := WithValue(Background(), k1, "c1k1")
+	check(c1, "c1", "c1k1", "", "")
+
+	if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
+		t.Errorf("c.String() = %q want %q", got, want)
+	}
+
+	c2 := WithValue(c1, k2, "c2k2")
+	check(c2, "c2", "c1k1", "c2k2", "")
+
+	c3 := WithValue(c2, k3, "c3k3")
+	check(c3, "c2", "c1k1", "c2k2", "c3k3")
+
+	c4 := WithValue(c3, k1, nil)
+	check(c4, "c4", "", "c2k2", "c3k3")
+
+	o0 := otherContext{Background()}
+	check(o0, "o0", "", "", "")
+
+	o1 := otherContext{WithValue(Background(), k1, "c1k1")}
+	check(o1, "o1", "c1k1", "", "")
+
+	o2 := WithValue(o1, k2, "o2k2")
+	check(o2, "o2", "c1k1", "o2k2", "")
+
+	o3 := otherContext{c4}
+	check(o3, "o3", "", "c2k2", "c3k3")
+
+	o4 := WithValue(o3, k3, nil)
+	check(o4, "o4", "", "c2k2", "")
+}
+
+func TestAllocs(t *testing.T) {
+	bg := Background()
+	for _, test := range []struct {
+		desc       string
+		f          func()
+		limit      float64
+		gccgoLimit float64
+	}{
+		{
+			desc:       "Background()",
+			f:          func() { Background() },
+			limit:      0,
+			gccgoLimit: 0,
+		},
+		{
+			desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
+			f: func() {
+				c := WithValue(bg, k1, nil)
+				c.Value(k1)
+			},
+			limit:      3,
+			gccgoLimit: 3,
+		},
+		{
+			desc: "WithTimeout(bg, 15*time.Millisecond)",
+			f: func() {
+				c, _ := WithTimeout(bg, 15*time.Millisecond)
+				<-c.Done()
+			},
+			limit:      8,
+			gccgoLimit: 16,
+		},
+		{
+			desc: "WithCancel(bg)",
+			f: func() {
+				c, cancel := WithCancel(bg)
+				cancel()
+				<-c.Done()
+			},
+			limit:      5,
+			gccgoLimit: 8,
+		},
+		{
+			desc: "WithTimeout(bg, 100*time.Millisecond)",
+			f: func() {
+				c, cancel := WithTimeout(bg, 100*time.Millisecond)
+				cancel()
+				<-c.Done()
+			},
+			limit:      8,
+			gccgoLimit: 25,
+		},
+	} {
+		limit := test.limit
+		if runtime.Compiler == "gccgo" {
+			// gccgo does not yet do escape analysis.
+			// TODO(iant): Remove this when gccgo does do escape analysis.
+			limit = test.gccgoLimit
+		}
+		if n := testing.AllocsPerRun(100, test.f); n > limit {
+			t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
+		}
+	}
+}
+
+func TestSimultaneousCancels(t *testing.T) {
+	root, cancel := WithCancel(Background())
+	m := map[Context]CancelFunc{root: cancel}
+	q := []Context{root}
+	// Create a tree of contexts.
+	for len(q) != 0 && len(m) < 100 {
+		parent := q[0]
+		q = q[1:]
+		for i := 0; i < 4; i++ {
+			ctx, cancel := WithCancel(parent)
+			m[ctx] = cancel
+			q = append(q, ctx)
+		}
+	}
+	// Start all the cancels in a random order.
+	var wg sync.WaitGroup
+	wg.Add(len(m))
+	for _, cancel := range m {
+		go func(cancel CancelFunc) {
+			cancel()
+			wg.Done()
+		}(cancel)
+	}
+	// Wait on all the contexts in a random order.
+	for ctx := range m {
+		select {
+		case <-ctx.Done():
+		case <-time.After(1 * time.Second):
+			buf := make([]byte, 10<<10)
+			n := runtime.Stack(buf, true)
+			t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
+		}
+	}
+	// Wait for all the cancel functions to return.
+	done := make(chan struct{})
+	go func() {
+		wg.Wait()
+		close(done)
+	}()
+	select {
+	case <-done:
+	case <-time.After(1 * time.Second):
+		buf := make([]byte, 10<<10)
+		n := runtime.Stack(buf, true)
+		t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
+	}
+}
+
+func TestInterlockedCancels(t *testing.T) {
+	parent, cancelParent := WithCancel(Background())
+	child, cancelChild := WithCancel(parent)
+	go func() {
+		parent.Done()
+		cancelChild()
+	}()
+	cancelParent()
+	select {
+	case <-child.Done():
+	case <-time.After(1 * time.Second):
+		buf := make([]byte, 10<<10)
+		n := runtime.Stack(buf, true)
+		t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
+	}
+}
+
+func TestLayersCancel(t *testing.T) {
+	testLayers(t, time.Now().UnixNano(), false)
+}
+
+func TestLayersTimeout(t *testing.T) {
+	testLayers(t, time.Now().UnixNano(), true)
+}
+
+func testLayers(t *testing.T, seed int64, testTimeout bool) {
+	rand.Seed(seed)
+	errorf := func(format string, a ...interface{}) {
+		t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
+	}
+	const (
+		timeout   = 200 * time.Millisecond
+		minLayers = 30
+	)
+	type value int
+	var (
+		vals      []*value
+		cancels   []CancelFunc
+		numTimers int
+		ctx       = Background()
+	)
+	for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
+		switch rand.Intn(3) {
+		case 0:
+			v := new(value)
+			ctx = WithValue(ctx, v, v)
+			vals = append(vals, v)
+		case 1:
+			var cancel CancelFunc
+			ctx, cancel = WithCancel(ctx)
+			cancels = append(cancels, cancel)
+		case 2:
+			var cancel CancelFunc
+			ctx, cancel = WithTimeout(ctx, timeout)
+			cancels = append(cancels, cancel)
+			numTimers++
+		}
+	}
+	checkValues := func(when string) {
+		for _, key := range vals {
+			if val := ctx.Value(key).(*value); key != val {
+				errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
+			}
+		}
+	}
+	select {
+	case <-ctx.Done():
+		errorf("ctx should not be canceled yet")
+	default:
+	}
+	if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
+		t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
+	}
+	t.Log(ctx)
+	checkValues("before cancel")
+	if testTimeout {
+		select {
+		case <-ctx.Done():
+		case <-time.After(timeout + 100*time.Millisecond):
+			errorf("ctx should have timed out")
+		}
+		checkValues("after timeout")
+	} else {
+		cancel := cancels[rand.Intn(len(cancels))]
+		cancel()
+		select {
+		case <-ctx.Done():
+		default:
+			errorf("ctx should be canceled")
+		}
+		checkValues("after cancel")
+	}
+}
+
+func TestCancelRemoves(t *testing.T) {
+	checkChildren := func(when string, ctx Context, want int) {
+		if got := len(ctx.(*cancelCtx).children); got != want {
+			t.Errorf("%s: context has %d children, want %d", when, got, want)
+		}
+	}
+
+	ctx, _ := WithCancel(Background())
+	checkChildren("after creation", ctx, 0)
+	_, cancel := WithCancel(ctx)
+	checkChildren("with WithCancel child ", ctx, 1)
+	cancel()
+	checkChildren("after cancelling WithCancel child", ctx, 0)
+
+	ctx, _ = WithCancel(Background())
+	checkChildren("after creation", ctx, 0)
+	_, cancel = WithTimeout(ctx, 60*time.Minute)
+	checkChildren("with WithTimeout child ", ctx, 1)
+	cancel()
+	checkChildren("after cancelling WithTimeout child", ctx, 0)
+}

+ 74 - 0
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go

@@ -0,0 +1,74 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
+package ctxhttp // import "golang.org/x/net/context/ctxhttp"
+
+import (
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+
+	"golang.org/x/net/context"
+)
+
+// Do sends an HTTP request with the provided http.Client and returns
+// an HTTP response.
+//
+// If the client is nil, http.DefaultClient is used.
+//
+// The provided ctx must be non-nil. If it is canceled or times out,
+// ctx.Err() will be returned.
+func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
+	if client == nil {
+		client = http.DefaultClient
+	}
+	resp, err := client.Do(req.WithContext(ctx))
+	// If we got an error, and the context has been canceled,
+	// the context's error is probably more useful.
+	if err != nil {
+		select {
+		case <-ctx.Done():
+			err = ctx.Err()
+		default:
+		}
+	}
+	return resp, err
+}
+
+// Get issues a GET request via the Do function.
+func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		return nil, err
+	}
+	return Do(ctx, client, req)
+}
+
+// Head issues a HEAD request via the Do function.
+func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+	req, err := http.NewRequest("HEAD", url, nil)
+	if err != nil {
+		return nil, err
+	}
+	return Do(ctx, client, req)
+}
+
+// Post issues a POST request via the Do function.
+func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
+	req, err := http.NewRequest("POST", url, body)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", bodyType)
+	return Do(ctx, client, req)
+}
+
+// PostForm issues a POST request via the Do function.
+func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
+	return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
+}

+ 29 - 0
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go

@@ -0,0 +1,29 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,go1.7
+
+package ctxhttp
+
+import (
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"context"
+)
+
+func TestGo17Context(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		io.WriteString(w, "ok")
+	}))
+	defer ts.Close()
+	ctx := context.Background()
+	resp, err := Get(ctx, http.DefaultClient, ts.URL)
+	if resp == nil || err != nil {
+		t.Fatalf("error received from client: %v %v", err, resp)
+	}
+	resp.Body.Close()
+}

+ 147 - 0
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go

@@ -0,0 +1,147 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7
+
+package ctxhttp // import "golang.org/x/net/context/ctxhttp"
+
+import (
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+
+	"golang.org/x/net/context"
+)
+
+func nop() {}
+
+var (
+	testHookContextDoneBeforeHeaders = nop
+	testHookDoReturned               = nop
+	testHookDidBodyClose             = nop
+)
+
+// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
+// If the client is nil, http.DefaultClient is used.
+// If the context is canceled or times out, ctx.Err() will be returned.
+func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
+	if client == nil {
+		client = http.DefaultClient
+	}
+
+	// TODO(djd): Respect any existing value of req.Cancel.
+	cancel := make(chan struct{})
+	req.Cancel = cancel
+
+	type responseAndError struct {
+		resp *http.Response
+		err  error
+	}
+	result := make(chan responseAndError, 1)
+
+	// Make local copies of test hooks closed over by goroutines below.
+	// Prevents data races in tests.
+	testHookDoReturned := testHookDoReturned
+	testHookDidBodyClose := testHookDidBodyClose
+
+	go func() {
+		resp, err := client.Do(req)
+		testHookDoReturned()
+		result <- responseAndError{resp, err}
+	}()
+
+	var resp *http.Response
+
+	select {
+	case <-ctx.Done():
+		testHookContextDoneBeforeHeaders()
+		close(cancel)
+		// Clean up after the goroutine calling client.Do:
+		go func() {
+			if r := <-result; r.resp != nil {
+				testHookDidBodyClose()
+				r.resp.Body.Close()
+			}
+		}()
+		return nil, ctx.Err()
+	case r := <-result:
+		var err error
+		resp, err = r.resp, r.err
+		if err != nil {
+			return resp, err
+		}
+	}
+
+	c := make(chan struct{})
+	go func() {
+		select {
+		case <-ctx.Done():
+			close(cancel)
+		case <-c:
+			// The response's Body is closed.
+		}
+	}()
+	resp.Body = &notifyingReader{resp.Body, c}
+
+	return resp, nil
+}
+
+// Get issues a GET request via the Do function.
+func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		return nil, err
+	}
+	return Do(ctx, client, req)
+}
+
+// Head issues a HEAD request via the Do function.
+func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+	req, err := http.NewRequest("HEAD", url, nil)
+	if err != nil {
+		return nil, err
+	}
+	return Do(ctx, client, req)
+}
+
+// Post issues a POST request via the Do function.
+func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
+	req, err := http.NewRequest("POST", url, body)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", bodyType)
+	return Do(ctx, client, req)
+}
+
+// PostForm issues a POST request via the Do function.
+func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
+	return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
+}
+
+// notifyingReader is an io.ReadCloser that closes the notify channel after
+// Close is called or a Read fails on the underlying ReadCloser.
+type notifyingReader struct {
+	io.ReadCloser
+	notify chan<- struct{}
+}
+
+func (r *notifyingReader) Read(p []byte) (int, error) {
+	n, err := r.ReadCloser.Read(p)
+	if err != nil && r.notify != nil {
+		close(r.notify)
+		r.notify = nil
+	}
+	return n, err
+}
+
+func (r *notifyingReader) Close() error {
+	err := r.ReadCloser.Close()
+	if r.notify != nil {
+		close(r.notify)
+		r.notify = nil
+	}
+	return err
+}

+ 79 - 0
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go

@@ -0,0 +1,79 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!go1.7
+
+package ctxhttp
+
+import (
+	"net"
+	"net/http"
+	"net/http/httptest"
+	"sync"
+	"testing"
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+// golang.org/issue/14065
+func TestClosesResponseBodyOnCancel(t *testing.T) {
+	defer func() { testHookContextDoneBeforeHeaders = nop }()
+	defer func() { testHookDoReturned = nop }()
+	defer func() { testHookDidBodyClose = nop }()
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+	defer ts.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+
+	// closed when Do enters select case <-ctx.Done()
+	enteredDonePath := make(chan struct{})
+
+	testHookContextDoneBeforeHeaders = func() {
+		close(enteredDonePath)
+	}
+
+	testHookDoReturned = func() {
+		// We now have the result (the Flush'd headers) at least,
+		// so we can cancel the request.
+		cancel()
+
+		// But block the client.Do goroutine from sending
+		// until Do enters into the <-ctx.Done() path, since
+		// otherwise if both channels are readable, select
+		// picks a random one.
+		<-enteredDonePath
+	}
+
+	sawBodyClose := make(chan struct{})
+	testHookDidBodyClose = func() { close(sawBodyClose) }
+
+	tr := &http.Transport{}
+	defer tr.CloseIdleConnections()
+	c := &http.Client{Transport: tr}
+	req, _ := http.NewRequest("GET", ts.URL, nil)
+	_, doErr := Do(ctx, c, req)
+
+	select {
+	case <-sawBodyClose:
+	case <-time.After(5 * time.Second):
+		t.Fatal("timeout waiting for body to close")
+	}
+
+	if doErr != ctx.Err() {
+		t.Errorf("Do error = %v; want %v", doErr, ctx.Err())
+	}
+}
+
+type noteCloseConn struct {
+	net.Conn
+	onceClose sync.Once
+	closefn   func()
+}
+
+func (c *noteCloseConn) Close() error {
+	c.onceClose.Do(c.closefn)
+	return c.Conn.Close()
+}

+ 105 - 0
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go

@@ -0,0 +1,105 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+package ctxhttp
+
+import (
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+const (
+	requestDuration = 100 * time.Millisecond
+	requestBody     = "ok"
+)
+
+func okHandler(w http.ResponseWriter, r *http.Request) {
+	time.Sleep(requestDuration)
+	io.WriteString(w, requestBody)
+}
+
+func TestNoTimeout(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(okHandler))
+	defer ts.Close()
+
+	ctx := context.Background()
+	res, err := Get(ctx, nil, ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	slurp, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(slurp) != requestBody {
+		t.Errorf("body = %q; want %q", slurp, requestBody)
+	}
+}
+
+func TestCancelBeforeHeaders(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+
+	blockServer := make(chan struct{})
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		cancel()
+		<-blockServer
+		io.WriteString(w, requestBody)
+	}))
+	defer ts.Close()
+	defer close(blockServer)
+
+	res, err := Get(ctx, nil, ts.URL)
+	if err == nil {
+		res.Body.Close()
+		t.Fatal("Get returned unexpected nil error")
+	}
+	if err != context.Canceled {
+		t.Errorf("err = %v; want %v", err, context.Canceled)
+	}
+}
+
+func TestCancelAfterHangingRequest(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusOK)
+		w.(http.Flusher).Flush()
+		<-w.(http.CloseNotifier).CloseNotify()
+	}))
+	defer ts.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	resp, err := Get(ctx, nil, ts.URL)
+	if err != nil {
+		t.Fatalf("unexpected error in Get: %v", err)
+	}
+
+	// Cancel befer reading the body.
+	// Reading Request.Body should fail, since the request was
+	// canceled before anything was written.
+	cancel()
+
+	done := make(chan struct{})
+
+	go func() {
+		b, err := ioutil.ReadAll(resp.Body)
+		if len(b) != 0 || err == nil {
+			t.Errorf(`Read got (%q, %v); want ("", error)`, b, err)
+		}
+		close(done)
+	}()
+
+	select {
+	case <-time.After(1 * time.Second):
+		t.Errorf("Test timed out")
+	case <-done:
+	}
+}

+ 72 - 0
vendor/golang.org/x/net/context/go17.go

@@ -0,0 +1,72 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package context
+
+import (
+	"context" // standard library's context, as of Go 1.7
+	"time"
+)
+
+var (
+	todo       = context.TODO()
+	background = context.Background()
+)
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = context.Canceled
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded = context.DeadlineExceeded
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+	ctx, f := context.WithCancel(parent)
+	return ctx, CancelFunc(f)
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
+	ctx, f := context.WithDeadline(parent, deadline)
+	return ctx, CancelFunc(f)
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// 	func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// 		ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// 		defer cancel()  // releases resources if slowOperation completes before timeout elapses
+// 		return slowOperation(ctx)
+// 	}
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+	return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+func WithValue(parent Context, key interface{}, val interface{}) Context {
+	return context.WithValue(parent, key, val)
+}

+ 20 - 0
vendor/golang.org/x/net/context/go19.go

@@ -0,0 +1,20 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.9
+
+package context
+
+import "context" // standard library's context, as of Go 1.7
+
+// A Context carries a deadline, a cancelation signal, and other values across
+// API boundaries.
+//
+// Context's methods may be called by multiple goroutines simultaneously.
+type Context = context.Context
+
+// A CancelFunc tells an operation to abandon its work.
+// A CancelFunc does not wait for the work to stop.
+// After the first call, subsequent calls to a CancelFunc do nothing.
+type CancelFunc = context.CancelFunc

+ 300 - 0
vendor/golang.org/x/net/context/pre_go17.go

@@ -0,0 +1,300 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7
+
+package context
+
+import (
+	"errors"
+	"fmt"
+	"sync"
+	"time"
+)
+
+// An emptyCtx is never canceled, has no values, and has no deadline. It is not
+// struct{}, since vars of this type must have distinct addresses.
+type emptyCtx int
+
+func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
+	return
+}
+
+func (*emptyCtx) Done() <-chan struct{} {
+	return nil
+}
+
+func (*emptyCtx) Err() error {
+	return nil
+}
+
+func (*emptyCtx) Value(key interface{}) interface{} {
+	return nil
+}
+
+func (e *emptyCtx) String() string {
+	switch e {
+	case background:
+		return "context.Background"
+	case todo:
+		return "context.TODO"
+	}
+	return "unknown empty Context"
+}
+
+var (
+	background = new(emptyCtx)
+	todo       = new(emptyCtx)
+)
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = errors.New("context canceled")
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded = errors.New("context deadline exceeded")
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+	c := newCancelCtx(parent)
+	propagateCancel(parent, c)
+	return c, func() { c.cancel(true, Canceled) }
+}
+
+// newCancelCtx returns an initialized cancelCtx.
+func newCancelCtx(parent Context) *cancelCtx {
+	return &cancelCtx{
+		Context: parent,
+		done:    make(chan struct{}),
+	}
+}
+
+// propagateCancel arranges for child to be canceled when parent is.
+func propagateCancel(parent Context, child canceler) {
+	if parent.Done() == nil {
+		return // parent is never canceled
+	}
+	if p, ok := parentCancelCtx(parent); ok {
+		p.mu.Lock()
+		if p.err != nil {
+			// parent has already been canceled
+			child.cancel(false, p.err)
+		} else {
+			if p.children == nil {
+				p.children = make(map[canceler]bool)
+			}
+			p.children[child] = true
+		}
+		p.mu.Unlock()
+	} else {
+		go func() {
+			select {
+			case <-parent.Done():
+				child.cancel(false, parent.Err())
+			case <-child.Done():
+			}
+		}()
+	}
+}
+
+// parentCancelCtx follows a chain of parent references until it finds a
+// *cancelCtx. This function understands how each of the concrete types in this
+// package represents its parent.
+func parentCancelCtx(parent Context) (*cancelCtx, bool) {
+	for {
+		switch c := parent.(type) {
+		case *cancelCtx:
+			return c, true
+		case *timerCtx:
+			return c.cancelCtx, true
+		case *valueCtx:
+			parent = c.Context
+		default:
+			return nil, false
+		}
+	}
+}
+
+// removeChild removes a context from its parent.
+func removeChild(parent Context, child canceler) {
+	p, ok := parentCancelCtx(parent)
+	if !ok {
+		return
+	}
+	p.mu.Lock()
+	if p.children != nil {
+		delete(p.children, child)
+	}
+	p.mu.Unlock()
+}
+
+// A canceler is a context type that can be canceled directly. The
+// implementations are *cancelCtx and *timerCtx.
+type canceler interface {
+	cancel(removeFromParent bool, err error)
+	Done() <-chan struct{}
+}
+
+// A cancelCtx can be canceled. When canceled, it also cancels any children
+// that implement canceler.
+type cancelCtx struct {
+	Context
+
+	done chan struct{} // closed by the first cancel call.
+
+	mu       sync.Mutex
+	children map[canceler]bool // set to nil by the first cancel call
+	err      error             // set to non-nil by the first cancel call
+}
+
+func (c *cancelCtx) Done() <-chan struct{} {
+	return c.done
+}
+
+func (c *cancelCtx) Err() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.err
+}
+
+func (c *cancelCtx) String() string {
+	return fmt.Sprintf("%v.WithCancel", c.Context)
+}
+
+// cancel closes c.done, cancels each of c's children, and, if
+// removeFromParent is true, removes c from its parent's children.
+func (c *cancelCtx) cancel(removeFromParent bool, err error) {
+	if err == nil {
+		panic("context: internal error: missing cancel error")
+	}
+	c.mu.Lock()
+	if c.err != nil {
+		c.mu.Unlock()
+		return // already canceled
+	}
+	c.err = err
+	close(c.done)
+	for child := range c.children {
+		// NOTE: acquiring the child's lock while holding parent's lock.
+		child.cancel(false, err)
+	}
+	c.children = nil
+	c.mu.Unlock()
+
+	if removeFromParent {
+		removeChild(c.Context, c)
+	}
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
+	if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
+		// The current deadline is already sooner than the new one.
+		return WithCancel(parent)
+	}
+	c := &timerCtx{
+		cancelCtx: newCancelCtx(parent),
+		deadline:  deadline,
+	}
+	propagateCancel(parent, c)
+	d := deadline.Sub(time.Now())
+	if d <= 0 {
+		c.cancel(true, DeadlineExceeded) // deadline has already passed
+		return c, func() { c.cancel(true, Canceled) }
+	}
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if c.err == nil {
+		c.timer = time.AfterFunc(d, func() {
+			c.cancel(true, DeadlineExceeded)
+		})
+	}
+	return c, func() { c.cancel(true, Canceled) }
+}
+
+// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
+// implement Done and Err. It implements cancel by stopping its timer then
+// delegating to cancelCtx.cancel.
+type timerCtx struct {
+	*cancelCtx
+	timer *time.Timer // Under cancelCtx.mu.
+
+	deadline time.Time
+}
+
+func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
+	return c.deadline, true
+}
+
+func (c *timerCtx) String() string {
+	return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
+}
+
+func (c *timerCtx) cancel(removeFromParent bool, err error) {
+	c.cancelCtx.cancel(false, err)
+	if removeFromParent {
+		// Remove this timerCtx from its parent cancelCtx's children.
+		removeChild(c.cancelCtx.Context, c)
+	}
+	c.mu.Lock()
+	if c.timer != nil {
+		c.timer.Stop()
+		c.timer = nil
+	}
+	c.mu.Unlock()
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// 	func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// 		ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// 		defer cancel()  // releases resources if slowOperation completes before timeout elapses
+// 		return slowOperation(ctx)
+// 	}
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+	return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+func WithValue(parent Context, key interface{}, val interface{}) Context {
+	return &valueCtx{parent, key, val}
+}
+
+// A valueCtx carries a key-value pair. It implements Value for that key and
+// delegates all other calls to the embedded Context.
+type valueCtx struct {
+	Context
+	key, val interface{}
+}
+
+func (c *valueCtx) String() string {
+	return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
+}
+
+func (c *valueCtx) Value(key interface{}) interface{} {
+	if c.key == key {
+		return c.val
+	}
+	return c.Context.Value(key)
+}

+ 109 - 0
vendor/golang.org/x/net/context/pre_go19.go

@@ -0,0 +1,109 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.9
+
+package context
+
+import "time"
+
+// A Context carries a deadline, a cancelation signal, and other values across
+// API boundaries.
+//
+// Context's methods may be called by multiple goroutines simultaneously.
+type Context interface {
+	// Deadline returns the time when work done on behalf of this context
+	// should be canceled. Deadline returns ok==false when no deadline is
+	// set. Successive calls to Deadline return the same results.
+	Deadline() (deadline time.Time, ok bool)
+
+	// Done returns a channel that's closed when work done on behalf of this
+	// context should be canceled. Done may return nil if this context can
+	// never be canceled. Successive calls to Done return the same value.
+	//
+	// WithCancel arranges for Done to be closed when cancel is called;
+	// WithDeadline arranges for Done to be closed when the deadline
+	// expires; WithTimeout arranges for Done to be closed when the timeout
+	// elapses.
+	//
+	// Done is provided for use in select statements:
+	//
+	//  // Stream generates values with DoSomething and sends them to out
+	//  // until DoSomething returns an error or ctx.Done is closed.
+	//  func Stream(ctx context.Context, out chan<- Value) error {
+	//  	for {
+	//  		v, err := DoSomething(ctx)
+	//  		if err != nil {
+	//  			return err
+	//  		}
+	//  		select {
+	//  		case <-ctx.Done():
+	//  			return ctx.Err()
+	//  		case out <- v:
+	//  		}
+	//  	}
+	//  }
+	//
+	// See http://blog.golang.org/pipelines for more examples of how to use
+	// a Done channel for cancelation.
+	Done() <-chan struct{}
+
+	// Err returns a non-nil error value after Done is closed. Err returns
+	// Canceled if the context was canceled or DeadlineExceeded if the
+	// context's deadline passed. No other values for Err are defined.
+	// After Done is closed, successive calls to Err return the same value.
+	Err() error
+
+	// Value returns the value associated with this context for key, or nil
+	// if no value is associated with key. Successive calls to Value with
+	// the same key returns the same result.
+	//
+	// Use context values only for request-scoped data that transits
+	// processes and API boundaries, not for passing optional parameters to
+	// functions.
+	//
+	// A key identifies a specific value in a Context. Functions that wish
+	// to store values in Context typically allocate a key in a global
+	// variable then use that key as the argument to context.WithValue and
+	// Context.Value. A key can be any type that supports equality;
+	// packages should define keys as an unexported type to avoid
+	// collisions.
+	//
+	// Packages that define a Context key should provide type-safe accessors
+	// for the values stores using that key:
+	//
+	// 	// Package user defines a User type that's stored in Contexts.
+	// 	package user
+	//
+	// 	import "golang.org/x/net/context"
+	//
+	// 	// User is the type of value stored in the Contexts.
+	// 	type User struct {...}
+	//
+	// 	// key is an unexported type for keys defined in this package.
+	// 	// This prevents collisions with keys defined in other packages.
+	// 	type key int
+	//
+	// 	// userKey is the key for user.User values in Contexts. It is
+	// 	// unexported; clients use user.NewContext and user.FromContext
+	// 	// instead of using this key directly.
+	// 	var userKey key = 0
+	//
+	// 	// NewContext returns a new Context that carries value u.
+	// 	func NewContext(ctx context.Context, u *User) context.Context {
+	// 		return context.WithValue(ctx, userKey, u)
+	// 	}
+	//
+	// 	// FromContext returns the User value stored in ctx, if any.
+	// 	func FromContext(ctx context.Context) (*User, bool) {
+	// 		u, ok := ctx.Value(userKey).(*User)
+	// 		return u, ok
+	// 	}
+	Value(key interface{}) interface{}
+}
+
+// A CancelFunc tells an operation to abandon its work.
+// A CancelFunc does not wait for the work to stop.
+// After the first call, subsequent calls to a CancelFunc do nothing.
+type CancelFunc func()

+ 31 - 0
vendor/golang.org/x/net/context/withtimeout_test.go

@@ -0,0 +1,31 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+	"fmt"
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+// This example passes a context with a timeout to tell a blocking function that
+// it should abandon its work after the timeout elapses.
+func ExampleWithTimeout() {
+	// Pass a context with a timeout to tell a blocking function that it
+	// should abandon its work after the timeout elapses.
+	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
+	defer cancel()
+
+	select {
+	case <-time.After(1 * time.Second):
+		fmt.Println("overslept")
+	case <-ctx.Done():
+		fmt.Println(ctx.Err()) // prints "context deadline exceeded"
+	}
+
+	// Output:
+	// context deadline exceeded
+}

+ 210 - 0
vendor/golang.org/x/net/dict/dict.go

@@ -0,0 +1,210 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dict implements the Dictionary Server Protocol
+// as defined in RFC 2229.
+package dict // import "golang.org/x/net/dict"
+
+import (
+	"net/textproto"
+	"strconv"
+	"strings"
+)
+
+// A Client represents a client connection to a dictionary server.
+type Client struct {
+	text *textproto.Conn
+}
+
+// Dial returns a new client connected to a dictionary server at
+// addr on the given network.
+func Dial(network, addr string) (*Client, error) {
+	text, err := textproto.Dial(network, addr)
+	if err != nil {
+		return nil, err
+	}
+	_, _, err = text.ReadCodeLine(220)
+	if err != nil {
+		text.Close()
+		return nil, err
+	}
+	return &Client{text: text}, nil
+}
+
+// Close closes the connection to the dictionary server.
+func (c *Client) Close() error {
+	return c.text.Close()
+}
+
+// A Dict represents a dictionary available on the server.
+type Dict struct {
+	Name string // short name of dictionary
+	Desc string // long description
+}
+
+// Dicts returns a list of the dictionaries available on the server.
+func (c *Client) Dicts() ([]Dict, error) {
+	id, err := c.text.Cmd("SHOW DB")
+	if err != nil {
+		return nil, err
+	}
+
+	c.text.StartResponse(id)
+	defer c.text.EndResponse(id)
+
+	_, _, err = c.text.ReadCodeLine(110)
+	if err != nil {
+		return nil, err
+	}
+	lines, err := c.text.ReadDotLines()
+	if err != nil {
+		return nil, err
+	}
+	_, _, err = c.text.ReadCodeLine(250)
+
+	dicts := make([]Dict, len(lines))
+	for i := range dicts {
+		d := &dicts[i]
+		a, _ := fields(lines[i])
+		if len(a) < 2 {
+			return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
+		}
+		d.Name = a[0]
+		d.Desc = a[1]
+	}
+	return dicts, err
+}
+
+// A Defn represents a definition.
+type Defn struct {
+	Dict Dict   // Dict where definition was found
+	Word string // Word being defined
+	Text []byte // Definition text, typically multiple lines
+}
+
+// Define requests the definition of the given word.
+// The argument dict names the dictionary to use,
+// the Name field of a Dict returned by Dicts.
+//
+// The special dictionary name "*" means to look in all the
+// server's dictionaries.
+// The special dictionary name "!" means to look in all the
+// server's dictionaries in turn, stopping after finding the word
+// in one of them.
+func (c *Client) Define(dict, word string) ([]*Defn, error) {
+	id, err := c.text.Cmd("DEFINE %s %q", dict, word)
+	if err != nil {
+		return nil, err
+	}
+
+	c.text.StartResponse(id)
+	defer c.text.EndResponse(id)
+
+	_, line, err := c.text.ReadCodeLine(150)
+	if err != nil {
+		return nil, err
+	}
+	a, _ := fields(line)
+	if len(a) < 1 {
+		return nil, textproto.ProtocolError("malformed response: " + line)
+	}
+	n, err := strconv.Atoi(a[0])
+	if err != nil {
+		return nil, textproto.ProtocolError("invalid definition count: " + a[0])
+	}
+	def := make([]*Defn, n)
+	for i := 0; i < n; i++ {
+		_, line, err = c.text.ReadCodeLine(151)
+		if err != nil {
+			return nil, err
+		}
+		a, _ := fields(line)
+		if len(a) < 3 {
+			// skip it, to keep protocol in sync
+			i--
+			n--
+			def = def[0:n]
+			continue
+		}
+		d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
+		d.Text, err = c.text.ReadDotBytes()
+		if err != nil {
+			return nil, err
+		}
+		def[i] = d
+	}
+	_, _, err = c.text.ReadCodeLine(250)
+	return def, err
+}
+
+// Fields returns the fields in s.
+// Fields are space separated unquoted words
+// or quoted with single or double quote.
+func fields(s string) ([]string, error) {
+	var v []string
+	i := 0
+	for {
+		for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+			i++
+		}
+		if i >= len(s) {
+			break
+		}
+		if s[i] == '"' || s[i] == '\'' {
+			q := s[i]
+			// quoted string
+			var j int
+			for j = i + 1; ; j++ {
+				if j >= len(s) {
+					return nil, textproto.ProtocolError("malformed quoted string")
+				}
+				if s[j] == '\\' {
+					j++
+					continue
+				}
+				if s[j] == q {
+					j++
+					break
+				}
+			}
+			v = append(v, unquote(s[i+1:j-1]))
+			i = j
+		} else {
+			// atom
+			var j int
+			for j = i; j < len(s); j++ {
+				if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
+					break
+				}
+			}
+			v = append(v, s[i:j])
+			i = j
+		}
+		if i < len(s) {
+			c := s[i]
+			if c != ' ' && c != '\t' {
+				return nil, textproto.ProtocolError("quotes not on word boundaries")
+			}
+		}
+	}
+	return v, nil
+}
+
+func unquote(s string) string {
+	if strings.Index(s, "\\") < 0 {
+		return s
+	}
+	b := []byte(s)
+	w := 0
+	for r := 0; r < len(b); r++ {
+		c := b[r]
+		if c == '\\' {
+			r++
+			c = b[r]
+		}
+		b[w] = c
+		w++
+	}
+	return string(b[0:w])
+}

+ 132 - 0
vendor/golang.org/x/net/dns/dnsmessage/example_test.go

@@ -0,0 +1,132 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dnsmessage_test
+
+import (
+	"fmt"
+	"net"
+	"strings"
+
+	"golang.org/x/net/dns/dnsmessage"
+)
+
+func mustNewName(name string) dnsmessage.Name {
+	n, err := dnsmessage.NewName(name)
+	if err != nil {
+		panic(err)
+	}
+	return n
+}
+
+func ExampleParser() {
+	msg := dnsmessage.Message{
+		Header: dnsmessage.Header{Response: true, Authoritative: true},
+		Questions: []dnsmessage.Question{
+			{
+				Name:  mustNewName("foo.bar.example.com."),
+				Type:  dnsmessage.TypeA,
+				Class: dnsmessage.ClassINET,
+			},
+			{
+				Name:  mustNewName("bar.example.com."),
+				Type:  dnsmessage.TypeA,
+				Class: dnsmessage.ClassINET,
+			},
+		},
+		Answers: []dnsmessage.Resource{
+			{
+				dnsmessage.ResourceHeader{
+					Name:  mustNewName("foo.bar.example.com."),
+					Type:  dnsmessage.TypeA,
+					Class: dnsmessage.ClassINET,
+				},
+				&dnsmessage.AResource{[4]byte{127, 0, 0, 1}},
+			},
+			{
+				dnsmessage.ResourceHeader{
+					Name:  mustNewName("bar.example.com."),
+					Type:  dnsmessage.TypeA,
+					Class: dnsmessage.ClassINET,
+				},
+				&dnsmessage.AResource{[4]byte{127, 0, 0, 2}},
+			},
+		},
+	}
+
+	buf, err := msg.Pack()
+	if err != nil {
+		panic(err)
+	}
+
+	wantName := "bar.example.com."
+
+	var p dnsmessage.Parser
+	if _, err := p.Start(buf); err != nil {
+		panic(err)
+	}
+
+	for {
+		q, err := p.Question()
+		if err == dnsmessage.ErrSectionDone {
+			break
+		}
+		if err != nil {
+			panic(err)
+		}
+
+		if q.Name.String() != wantName {
+			continue
+		}
+
+		fmt.Println("Found question for name", wantName)
+		if err := p.SkipAllQuestions(); err != nil {
+			panic(err)
+		}
+		break
+	}
+
+	var gotIPs []net.IP
+	for {
+		h, err := p.AnswerHeader()
+		if err == dnsmessage.ErrSectionDone {
+			break
+		}
+		if err != nil {
+			panic(err)
+		}
+
+		if (h.Type != dnsmessage.TypeA && h.Type != dnsmessage.TypeAAAA) || h.Class != dnsmessage.ClassINET {
+			continue
+		}
+
+		if !strings.EqualFold(h.Name.String(), wantName) {
+			if err := p.SkipAnswer(); err != nil {
+				panic(err)
+			}
+			continue
+		}
+
+		switch h.Type {
+		case dnsmessage.TypeA:
+			r, err := p.AResource()
+			if err != nil {
+				panic(err)
+			}
+			gotIPs = append(gotIPs, r.A[:])
+		case dnsmessage.TypeAAAA:
+			r, err := p.AAAAResource()
+			if err != nil {
+				panic(err)
+			}
+			gotIPs = append(gotIPs, r.AAAA[:])
+		}
+	}
+
+	fmt.Printf("Found A/AAAA records for name %s: %v\n", wantName, gotIPs)
+
+	// Output:
+	// Found question for name bar.example.com.
+	// Found A/AAAA records for name bar.example.com.: [127.0.0.2]
+}

+ 1997 - 0
vendor/golang.org/x/net/dns/dnsmessage/message.go

@@ -0,0 +1,1997 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dnsmessage provides a mostly RFC 1035 compliant implementation of
+// DNS message packing and unpacking.
+//
+// This implementation is designed to minimize heap allocations and avoid
+// unnecessary packing and unpacking as much as possible.
+package dnsmessage
+
+import (
+	"errors"
+)
+
+// Packet formats
+
+// A Type is a type of DNS request and response.
+type Type uint16
+
+// A Class is a type of network.
+type Class uint16
+
+// An OpCode is a DNS operation code.
+type OpCode uint16
+
+// An RCode is a DNS response status code.
+type RCode uint16
+
+// Wire constants.
+const (
+	// ResourceHeader.Type and Question.Type
+	TypeA     Type = 1
+	TypeNS    Type = 2
+	TypeCNAME Type = 5
+	TypeSOA   Type = 6
+	TypePTR   Type = 12
+	TypeMX    Type = 15
+	TypeTXT   Type = 16
+	TypeAAAA  Type = 28
+	TypeSRV   Type = 33
+
+	// Question.Type
+	TypeWKS   Type = 11
+	TypeHINFO Type = 13
+	TypeMINFO Type = 14
+	TypeAXFR  Type = 252
+	TypeALL   Type = 255
+
+	// ResourceHeader.Class and Question.Class
+	ClassINET   Class = 1
+	ClassCSNET  Class = 2
+	ClassCHAOS  Class = 3
+	ClassHESIOD Class = 4
+
+	// Question.Class
+	ClassANY Class = 255
+
+	// Message.Rcode
+	RCodeSuccess        RCode = 0
+	RCodeFormatError    RCode = 1
+	RCodeServerFailure  RCode = 2
+	RCodeNameError      RCode = 3
+	RCodeNotImplemented RCode = 4
+	RCodeRefused        RCode = 5
+)
+
+var (
+	// ErrNotStarted indicates that the prerequisite information isn't
+	// available yet because the previous records haven't been appropriately
+	// parsed, skipped or finished.
+	ErrNotStarted = errors.New("parsing/packing of this type isn't available yet")
+
+	// ErrSectionDone indicated that all records in the section have been
+	// parsed or finished.
+	ErrSectionDone = errors.New("parsing/packing of this section has completed")
+
+	errBaseLen            = errors.New("insufficient data for base length type")
+	errCalcLen            = errors.New("insufficient data for calculated length type")
+	errReserved           = errors.New("segment prefix is reserved")
+	errTooManyPtr         = errors.New("too many pointers (>10)")
+	errInvalidPtr         = errors.New("invalid pointer")
+	errNilResouceBody     = errors.New("nil resource body")
+	errResourceLen        = errors.New("insufficient data for resource body length")
+	errSegTooLong         = errors.New("segment length too long")
+	errZeroSegLen         = errors.New("zero length segment")
+	errResTooLong         = errors.New("resource length too long")
+	errTooManyQuestions   = errors.New("too many Questions to pack (>65535)")
+	errTooManyAnswers     = errors.New("too many Answers to pack (>65535)")
+	errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)")
+	errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)")
+	errNonCanonicalName   = errors.New("name is not in canonical format (it must end with a .)")
+)
+
+// Internal constants.
+const (
+	// packStartingCap is the default initial buffer size allocated during
+	// packing.
+	//
+	// The starting capacity doesn't matter too much, but most DNS responses
+	// Will be <= 512 bytes as it is the limit for DNS over UDP.
+	packStartingCap = 512
+
+	// uint16Len is the length (in bytes) of a uint16.
+	uint16Len = 2
+
+	// uint32Len is the length (in bytes) of a uint32.
+	uint32Len = 4
+
+	// headerLen is the length (in bytes) of a DNS header.
+	//
+	// A header is comprised of 6 uint16s and no padding.
+	headerLen = 6 * uint16Len
+)
+
+type nestedError struct {
+	// s is the current level's error message.
+	s string
+
+	// err is the nested error.
+	err error
+}
+
+// nestedError implements error.Error.
+func (e *nestedError) Error() string {
+	return e.s + ": " + e.err.Error()
+}
+
+// Header is a representation of a DNS message header.
+type Header struct {
+	ID                 uint16
+	Response           bool
+	OpCode             OpCode
+	Authoritative      bool
+	Truncated          bool
+	RecursionDesired   bool
+	RecursionAvailable bool
+	RCode              RCode
+}
+
+func (m *Header) pack() (id uint16, bits uint16) {
+	id = m.ID
+	bits = uint16(m.OpCode)<<11 | uint16(m.RCode)
+	if m.RecursionAvailable {
+		bits |= headerBitRA
+	}
+	if m.RecursionDesired {
+		bits |= headerBitRD
+	}
+	if m.Truncated {
+		bits |= headerBitTC
+	}
+	if m.Authoritative {
+		bits |= headerBitAA
+	}
+	if m.Response {
+		bits |= headerBitQR
+	}
+	return
+}
+
+// Message is a representation of a DNS message.
+type Message struct {
+	Header
+	Questions   []Question
+	Answers     []Resource
+	Authorities []Resource
+	Additionals []Resource
+}
+
+type section uint8
+
+const (
+	sectionNotStarted section = iota
+	sectionHeader
+	sectionQuestions
+	sectionAnswers
+	sectionAuthorities
+	sectionAdditionals
+	sectionDone
+
+	headerBitQR = 1 << 15 // query/response (response=1)
+	headerBitAA = 1 << 10 // authoritative
+	headerBitTC = 1 << 9  // truncated
+	headerBitRD = 1 << 8  // recursion desired
+	headerBitRA = 1 << 7  // recursion available
+)
+
+var sectionNames = map[section]string{
+	sectionHeader:      "header",
+	sectionQuestions:   "Question",
+	sectionAnswers:     "Answer",
+	sectionAuthorities: "Authority",
+	sectionAdditionals: "Additional",
+}
+
+// header is the wire format for a DNS message header.
+type header struct {
+	id          uint16
+	bits        uint16
+	questions   uint16
+	answers     uint16
+	authorities uint16
+	additionals uint16
+}
+
+func (h *header) count(sec section) uint16 {
+	switch sec {
+	case sectionQuestions:
+		return h.questions
+	case sectionAnswers:
+		return h.answers
+	case sectionAuthorities:
+		return h.authorities
+	case sectionAdditionals:
+		return h.additionals
+	}
+	return 0
+}
+
+func (h *header) pack(msg []byte) []byte {
+	msg = packUint16(msg, h.id)
+	msg = packUint16(msg, h.bits)
+	msg = packUint16(msg, h.questions)
+	msg = packUint16(msg, h.answers)
+	msg = packUint16(msg, h.authorities)
+	return packUint16(msg, h.additionals)
+}
+
+func (h *header) unpack(msg []byte, off int) (int, error) {
+	newOff := off
+	var err error
+	if h.id, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"id", err}
+	}
+	if h.bits, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"bits", err}
+	}
+	if h.questions, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"questions", err}
+	}
+	if h.answers, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"answers", err}
+	}
+	if h.authorities, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"authorities", err}
+	}
+	if h.additionals, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"additionals", err}
+	}
+	return newOff, nil
+}
+
+func (h *header) header() Header {
+	return Header{
+		ID:                 h.id,
+		Response:           (h.bits & headerBitQR) != 0,
+		OpCode:             OpCode(h.bits>>11) & 0xF,
+		Authoritative:      (h.bits & headerBitAA) != 0,
+		Truncated:          (h.bits & headerBitTC) != 0,
+		RecursionDesired:   (h.bits & headerBitRD) != 0,
+		RecursionAvailable: (h.bits & headerBitRA) != 0,
+		RCode:              RCode(h.bits & 0xF),
+	}
+}
+
+// A Resource is a DNS resource record.
+type Resource struct {
+	Header ResourceHeader
+	Body   ResourceBody
+}
+
+// A ResourceBody is a DNS resource record minus the header.
+type ResourceBody interface {
+	// pack packs a Resource except for its header.
+	pack(msg []byte, compression map[string]int) ([]byte, error)
+
+	// realType returns the actual type of the Resource. This is used to
+	// fill in the header Type field.
+	realType() Type
+}
+
+func (r *Resource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	if r.Body == nil {
+		return msg, errNilResouceBody
+	}
+	oldMsg := msg
+	r.Header.Type = r.Body.realType()
+	msg, length, err := r.Header.pack(msg, compression)
+	if err != nil {
+		return msg, &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	msg, err = r.Body.pack(msg, compression)
+	if err != nil {
+		return msg, &nestedError{"content", err}
+	}
+	if err := r.Header.fixLen(msg, length, preLen); err != nil {
+		return oldMsg, err
+	}
+	return msg, nil
+}
+
+// A Parser allows incrementally parsing a DNS message.
+//
+// When parsing is started, the Header is parsed. Next, each Question can be
+// either parsed or skipped. Alternatively, all Questions can be skipped at
+// once. When all Questions have been parsed, attempting to parse Questions
+// will return (nil, nil) and attempting to skip Questions will return
+// (true, nil). After all Questions have been either parsed or skipped, all
+// Answers, Authorities and Additionals can be either parsed or skipped in the
+// same way, and each type of Resource must be fully parsed or skipped before
+// proceeding to the next type of Resource.
+//
+// Note that there is no requirement to fully skip or parse the message.
+type Parser struct {
+	msg    []byte
+	header header
+
+	section        section
+	off            int
+	index          int
+	resHeaderValid bool
+	resHeader      ResourceHeader
+}
+
+// Start parses the header and enables the parsing of Questions.
+func (p *Parser) Start(msg []byte) (Header, error) {
+	if p.msg != nil {
+		*p = Parser{}
+	}
+	p.msg = msg
+	var err error
+	if p.off, err = p.header.unpack(msg, 0); err != nil {
+		return Header{}, &nestedError{"unpacking header", err}
+	}
+	p.section = sectionQuestions
+	return p.header.header(), nil
+}
+
+func (p *Parser) checkAdvance(sec section) error {
+	if p.section < sec {
+		return ErrNotStarted
+	}
+	if p.section > sec {
+		return ErrSectionDone
+	}
+	p.resHeaderValid = false
+	if p.index == int(p.header.count(sec)) {
+		p.index = 0
+		p.section++
+		return ErrSectionDone
+	}
+	return nil
+}
+
+func (p *Parser) resource(sec section) (Resource, error) {
+	var r Resource
+	var err error
+	r.Header, err = p.resourceHeader(sec)
+	if err != nil {
+		return r, err
+	}
+	p.resHeaderValid = false
+	r.Body, p.off, err = unpackResourceBody(p.msg, p.off, r.Header)
+	if err != nil {
+		return Resource{}, &nestedError{"unpacking " + sectionNames[sec], err}
+	}
+	p.index++
+	return r, nil
+}
+
+func (p *Parser) resourceHeader(sec section) (ResourceHeader, error) {
+	if p.resHeaderValid {
+		return p.resHeader, nil
+	}
+	if err := p.checkAdvance(sec); err != nil {
+		return ResourceHeader{}, err
+	}
+	var hdr ResourceHeader
+	off, err := hdr.unpack(p.msg, p.off)
+	if err != nil {
+		return ResourceHeader{}, err
+	}
+	p.resHeaderValid = true
+	p.resHeader = hdr
+	p.off = off
+	return hdr, nil
+}
+
+func (p *Parser) skipResource(sec section) error {
+	if p.resHeaderValid {
+		newOff := p.off + int(p.resHeader.Length)
+		if newOff > len(p.msg) {
+			return errResourceLen
+		}
+		p.off = newOff
+		p.resHeaderValid = false
+		p.index++
+		return nil
+	}
+	if err := p.checkAdvance(sec); err != nil {
+		return err
+	}
+	var err error
+	p.off, err = skipResource(p.msg, p.off)
+	if err != nil {
+		return &nestedError{"skipping: " + sectionNames[sec], err}
+	}
+	p.index++
+	return nil
+}
+
+// Question parses a single Question.
+func (p *Parser) Question() (Question, error) {
+	if err := p.checkAdvance(sectionQuestions); err != nil {
+		return Question{}, err
+	}
+	var name Name
+	off, err := name.unpack(p.msg, p.off)
+	if err != nil {
+		return Question{}, &nestedError{"unpacking Question.Name", err}
+	}
+	typ, off, err := unpackType(p.msg, off)
+	if err != nil {
+		return Question{}, &nestedError{"unpacking Question.Type", err}
+	}
+	class, off, err := unpackClass(p.msg, off)
+	if err != nil {
+		return Question{}, &nestedError{"unpacking Question.Class", err}
+	}
+	p.off = off
+	p.index++
+	return Question{name, typ, class}, nil
+}
+
+// AllQuestions parses all Questions.
+func (p *Parser) AllQuestions() ([]Question, error) {
+	qs := make([]Question, 0, p.header.questions)
+	for {
+		q, err := p.Question()
+		if err == ErrSectionDone {
+			return qs, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+		qs = append(qs, q)
+	}
+}
+
+// SkipQuestion skips a single Question.
+func (p *Parser) SkipQuestion() error {
+	if err := p.checkAdvance(sectionQuestions); err != nil {
+		return err
+	}
+	off, err := skipName(p.msg, p.off)
+	if err != nil {
+		return &nestedError{"skipping Question Name", err}
+	}
+	if off, err = skipType(p.msg, off); err != nil {
+		return &nestedError{"skipping Question Type", err}
+	}
+	if off, err = skipClass(p.msg, off); err != nil {
+		return &nestedError{"skipping Question Class", err}
+	}
+	p.off = off
+	p.index++
+	return nil
+}
+
+// SkipAllQuestions skips all Questions.
+func (p *Parser) SkipAllQuestions() error {
+	for {
+		if err := p.SkipQuestion(); err == ErrSectionDone {
+			return nil
+		} else if err != nil {
+			return err
+		}
+	}
+}
+
+// AnswerHeader parses a single Answer ResourceHeader.
+func (p *Parser) AnswerHeader() (ResourceHeader, error) {
+	return p.resourceHeader(sectionAnswers)
+}
+
+// Answer parses a single Answer Resource.
+func (p *Parser) Answer() (Resource, error) {
+	return p.resource(sectionAnswers)
+}
+
+// AllAnswers parses all Answer Resources.
+func (p *Parser) AllAnswers() ([]Resource, error) {
+	as := make([]Resource, 0, p.header.answers)
+	for {
+		a, err := p.Answer()
+		if err == ErrSectionDone {
+			return as, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+		as = append(as, a)
+	}
+}
+
+// SkipAnswer skips a single Answer Resource.
+func (p *Parser) SkipAnswer() error {
+	return p.skipResource(sectionAnswers)
+}
+
+// SkipAllAnswers skips all Answer Resources.
+func (p *Parser) SkipAllAnswers() error {
+	for {
+		if err := p.SkipAnswer(); err == ErrSectionDone {
+			return nil
+		} else if err != nil {
+			return err
+		}
+	}
+}
+
+// AuthorityHeader parses a single Authority ResourceHeader.
+func (p *Parser) AuthorityHeader() (ResourceHeader, error) {
+	return p.resourceHeader(sectionAuthorities)
+}
+
+// Authority parses a single Authority Resource.
+func (p *Parser) Authority() (Resource, error) {
+	return p.resource(sectionAuthorities)
+}
+
+// AllAuthorities parses all Authority Resources.
+func (p *Parser) AllAuthorities() ([]Resource, error) {
+	as := make([]Resource, 0, p.header.authorities)
+	for {
+		a, err := p.Authority()
+		if err == ErrSectionDone {
+			return as, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+		as = append(as, a)
+	}
+}
+
+// SkipAuthority skips a single Authority Resource.
+func (p *Parser) SkipAuthority() error {
+	return p.skipResource(sectionAuthorities)
+}
+
+// SkipAllAuthorities skips all Authority Resources.
+func (p *Parser) SkipAllAuthorities() error {
+	for {
+		if err := p.SkipAuthority(); err == ErrSectionDone {
+			return nil
+		} else if err != nil {
+			return err
+		}
+	}
+}
+
+// AdditionalHeader parses a single Additional ResourceHeader.
+func (p *Parser) AdditionalHeader() (ResourceHeader, error) {
+	return p.resourceHeader(sectionAdditionals)
+}
+
+// Additional parses a single Additional Resource.
+func (p *Parser) Additional() (Resource, error) {
+	return p.resource(sectionAdditionals)
+}
+
+// AllAdditionals parses all Additional Resources.
+func (p *Parser) AllAdditionals() ([]Resource, error) {
+	as := make([]Resource, 0, p.header.additionals)
+	for {
+		a, err := p.Additional()
+		if err == ErrSectionDone {
+			return as, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+		as = append(as, a)
+	}
+}
+
+// SkipAdditional skips a single Additional Resource.
+func (p *Parser) SkipAdditional() error {
+	return p.skipResource(sectionAdditionals)
+}
+
+// SkipAllAdditionals skips all Additional Resources.
+func (p *Parser) SkipAllAdditionals() error {
+	for {
+		if err := p.SkipAdditional(); err == ErrSectionDone {
+			return nil
+		} else if err != nil {
+			return err
+		}
+	}
+}
+
+// CNAMEResource parses a single CNAMEResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) CNAMEResource() (CNAMEResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeCNAME {
+		return CNAMEResource{}, ErrNotStarted
+	}
+	r, err := unpackCNAMEResource(p.msg, p.off)
+	if err != nil {
+		return CNAMEResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// MXResource parses a single MXResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) MXResource() (MXResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeMX {
+		return MXResource{}, ErrNotStarted
+	}
+	r, err := unpackMXResource(p.msg, p.off)
+	if err != nil {
+		return MXResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// NSResource parses a single NSResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) NSResource() (NSResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeNS {
+		return NSResource{}, ErrNotStarted
+	}
+	r, err := unpackNSResource(p.msg, p.off)
+	if err != nil {
+		return NSResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// PTRResource parses a single PTRResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) PTRResource() (PTRResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypePTR {
+		return PTRResource{}, ErrNotStarted
+	}
+	r, err := unpackPTRResource(p.msg, p.off)
+	if err != nil {
+		return PTRResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// SOAResource parses a single SOAResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) SOAResource() (SOAResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeSOA {
+		return SOAResource{}, ErrNotStarted
+	}
+	r, err := unpackSOAResource(p.msg, p.off)
+	if err != nil {
+		return SOAResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// TXTResource parses a single TXTResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) TXTResource() (TXTResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeTXT {
+		return TXTResource{}, ErrNotStarted
+	}
+	r, err := unpackTXTResource(p.msg, p.off, p.resHeader.Length)
+	if err != nil {
+		return TXTResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// SRVResource parses a single SRVResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) SRVResource() (SRVResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeSRV {
+		return SRVResource{}, ErrNotStarted
+	}
+	r, err := unpackSRVResource(p.msg, p.off)
+	if err != nil {
+		return SRVResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// AResource parses a single AResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) AResource() (AResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeA {
+		return AResource{}, ErrNotStarted
+	}
+	r, err := unpackAResource(p.msg, p.off)
+	if err != nil {
+		return AResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// AAAAResource parses a single AAAAResource.
+//
+// One of the XXXHeader methods must have been called before calling this
+// method.
+func (p *Parser) AAAAResource() (AAAAResource, error) {
+	if !p.resHeaderValid || p.resHeader.Type != TypeAAAA {
+		return AAAAResource{}, ErrNotStarted
+	}
+	r, err := unpackAAAAResource(p.msg, p.off)
+	if err != nil {
+		return AAAAResource{}, err
+	}
+	p.off += int(p.resHeader.Length)
+	p.resHeaderValid = false
+	p.index++
+	return r, nil
+}
+
+// Unpack parses a full Message.
+func (m *Message) Unpack(msg []byte) error {
+	var p Parser
+	var err error
+	if m.Header, err = p.Start(msg); err != nil {
+		return err
+	}
+	if m.Questions, err = p.AllQuestions(); err != nil {
+		return err
+	}
+	if m.Answers, err = p.AllAnswers(); err != nil {
+		return err
+	}
+	if m.Authorities, err = p.AllAuthorities(); err != nil {
+		return err
+	}
+	if m.Additionals, err = p.AllAdditionals(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// Pack packs a full Message.
+func (m *Message) Pack() ([]byte, error) {
+	// Validate the lengths. It is very unlikely that anyone will try to
+	// pack more than 65535 of any particular type, but it is possible and
+	// we should fail gracefully.
+	if len(m.Questions) > int(^uint16(0)) {
+		return nil, errTooManyQuestions
+	}
+	if len(m.Answers) > int(^uint16(0)) {
+		return nil, errTooManyAnswers
+	}
+	if len(m.Authorities) > int(^uint16(0)) {
+		return nil, errTooManyAuthorities
+	}
+	if len(m.Additionals) > int(^uint16(0)) {
+		return nil, errTooManyAdditionals
+	}
+
+	var h header
+	h.id, h.bits = m.Header.pack()
+
+	h.questions = uint16(len(m.Questions))
+	h.answers = uint16(len(m.Answers))
+	h.authorities = uint16(len(m.Authorities))
+	h.additionals = uint16(len(m.Additionals))
+
+	msg := make([]byte, 0, packStartingCap)
+
+	msg = h.pack(msg)
+
+	// RFC 1035 allows (but does not require) compression for packing. RFC
+	// 1035 requires unpacking implementations to support compression, so
+	// unconditionally enabling it is fine.
+	//
+	// DNS lookups are typically done over UDP, and RFC 1035 states that UDP
+	// DNS packets can be a maximum of 512 bytes long. Without compression,
+	// many DNS response packets are over this limit, so enabling
+	// compression will help ensure compliance.
+	compression := map[string]int{}
+
+	for i := range m.Questions {
+		var err error
+		if msg, err = m.Questions[i].pack(msg, compression); err != nil {
+			return nil, &nestedError{"packing Question", err}
+		}
+	}
+	for i := range m.Answers {
+		var err error
+		if msg, err = m.Answers[i].pack(msg, compression); err != nil {
+			return nil, &nestedError{"packing Answer", err}
+		}
+	}
+	for i := range m.Authorities {
+		var err error
+		if msg, err = m.Authorities[i].pack(msg, compression); err != nil {
+			return nil, &nestedError{"packing Authority", err}
+		}
+	}
+	for i := range m.Additionals {
+		var err error
+		if msg, err = m.Additionals[i].pack(msg, compression); err != nil {
+			return nil, &nestedError{"packing Additional", err}
+		}
+	}
+
+	return msg, nil
+}
+
+// A Builder allows incrementally packing a DNS message.
+type Builder struct {
+	msg         []byte
+	header      header
+	section     section
+	compression map[string]int
+}
+
+// Start initializes the builder.
+//
+// buf is optional (nil is fine), but if provided, Start takes ownership of buf.
+func (b *Builder) Start(buf []byte, h Header) {
+	b.StartWithoutCompression(buf, h)
+	b.compression = map[string]int{}
+}
+
+// StartWithoutCompression initializes the builder with compression disabled.
+//
+// This avoids compression related allocations, but can result in larger message
+// sizes. Be careful with this mode as it can cause messages to exceed the UDP
+// size limit.
+//
+// buf is optional (nil is fine), but if provided, Start takes ownership of buf.
+func (b *Builder) StartWithoutCompression(buf []byte, h Header) {
+	*b = Builder{msg: buf}
+	b.header.id, b.header.bits = h.pack()
+	if cap(b.msg) < headerLen {
+		b.msg = make([]byte, 0, packStartingCap)
+	}
+	b.msg = b.msg[:headerLen]
+	b.section = sectionHeader
+}
+
+func (b *Builder) startCheck(s section) error {
+	if b.section <= sectionNotStarted {
+		return ErrNotStarted
+	}
+	if b.section > s {
+		return ErrSectionDone
+	}
+	return nil
+}
+
+// StartQuestions prepares the builder for packing Questions.
+func (b *Builder) StartQuestions() error {
+	if err := b.startCheck(sectionQuestions); err != nil {
+		return err
+	}
+	b.section = sectionQuestions
+	return nil
+}
+
+// StartAnswers prepares the builder for packing Answers.
+func (b *Builder) StartAnswers() error {
+	if err := b.startCheck(sectionAnswers); err != nil {
+		return err
+	}
+	b.section = sectionAnswers
+	return nil
+}
+
+// StartAuthorities prepares the builder for packing Authorities.
+func (b *Builder) StartAuthorities() error {
+	if err := b.startCheck(sectionAuthorities); err != nil {
+		return err
+	}
+	b.section = sectionAuthorities
+	return nil
+}
+
+// StartAdditionals prepares the builder for packing Additionals.
+func (b *Builder) StartAdditionals() error {
+	if err := b.startCheck(sectionAdditionals); err != nil {
+		return err
+	}
+	b.section = sectionAdditionals
+	return nil
+}
+
+func (b *Builder) incrementSectionCount() error {
+	var count *uint16
+	var err error
+	switch b.section {
+	case sectionQuestions:
+		count = &b.header.questions
+		err = errTooManyQuestions
+	case sectionAnswers:
+		count = &b.header.answers
+		err = errTooManyAnswers
+	case sectionAuthorities:
+		count = &b.header.authorities
+		err = errTooManyAuthorities
+	case sectionAdditionals:
+		count = &b.header.additionals
+		err = errTooManyAdditionals
+	}
+	if *count == ^uint16(0) {
+		return err
+	}
+	*count++
+	return nil
+}
+
+// Question adds a single Question.
+func (b *Builder) Question(q Question) error {
+	if b.section < sectionQuestions {
+		return ErrNotStarted
+	}
+	if b.section > sectionQuestions {
+		return ErrSectionDone
+	}
+	msg, err := q.pack(b.msg, b.compression)
+	if err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+func (b *Builder) checkResourceSection() error {
+	if b.section < sectionAnswers {
+		return ErrNotStarted
+	}
+	if b.section > sectionAdditionals {
+		return ErrSectionDone
+	}
+	return nil
+}
+
+// CNAMEResource adds a single CNAMEResource.
+func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"CNAMEResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// MXResource adds a single MXResource.
+func (b *Builder) MXResource(h ResourceHeader, r MXResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"MXResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// NSResource adds a single NSResource.
+func (b *Builder) NSResource(h ResourceHeader, r NSResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"NSResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// PTRResource adds a single PTRResource.
+func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"PTRResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// SOAResource adds a single SOAResource.
+func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"SOAResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// TXTResource adds a single TXTResource.
+func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"TXTResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// SRVResource adds a single SRVResource.
+func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"SRVResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// AResource adds a single AResource.
+func (b *Builder) AResource(h ResourceHeader, r AResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"AResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// AAAAResource adds a single AAAAResource.
+func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error {
+	if err := b.checkResourceSection(); err != nil {
+		return err
+	}
+	h.Type = r.realType()
+	msg, length, err := h.pack(b.msg, b.compression)
+	if err != nil {
+		return &nestedError{"ResourceHeader", err}
+	}
+	preLen := len(msg)
+	if msg, err = r.pack(msg, b.compression); err != nil {
+		return &nestedError{"AAAAResource body", err}
+	}
+	if err := h.fixLen(msg, length, preLen); err != nil {
+		return err
+	}
+	if err := b.incrementSectionCount(); err != nil {
+		return err
+	}
+	b.msg = msg
+	return nil
+}
+
+// Finish ends message building and generates a binary packet.
+func (b *Builder) Finish() ([]byte, error) {
+	if b.section < sectionHeader {
+		return nil, ErrNotStarted
+	}
+	b.section = sectionDone
+	b.header.pack(b.msg[:0])
+	return b.msg, nil
+}
+
+// A ResourceHeader is the header of a DNS resource record. There are
+// many types of DNS resource records, but they all share the same header.
+type ResourceHeader struct {
+	// Name is the domain name for which this resource record pertains.
+	Name Name
+
+	// Type is the type of DNS resource record.
+	//
+	// This field will be set automatically during packing.
+	Type Type
+
+	// Class is the class of network to which this DNS resource record
+	// pertains.
+	Class Class
+
+	// TTL is the length of time (measured in seconds) which this resource
+	// record is valid for (time to live). All Resources in a set should
+	// have the same TTL (RFC 2181 Section 5.2).
+	TTL uint32
+
+	// Length is the length of data in the resource record after the header.
+	//
+	// This field will be set automatically during packing.
+	Length uint16
+}
+
+// pack packs all of the fields in a ResourceHeader except for the length. The
+// length bytes are returned as a slice so they can be filled in after the rest
+// of the Resource has been packed.
+func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]int) (msg []byte, length []byte, err error) {
+	msg = oldMsg
+	if msg, err = h.Name.pack(msg, compression); err != nil {
+		return oldMsg, nil, &nestedError{"Name", err}
+	}
+	msg = packType(msg, h.Type)
+	msg = packClass(msg, h.Class)
+	msg = packUint32(msg, h.TTL)
+	lenBegin := len(msg)
+	msg = packUint16(msg, h.Length)
+	return msg, msg[lenBegin : lenBegin+uint16Len], nil
+}
+
+func (h *ResourceHeader) unpack(msg []byte, off int) (int, error) {
+	newOff := off
+	var err error
+	if newOff, err = h.Name.unpack(msg, newOff); err != nil {
+		return off, &nestedError{"Name", err}
+	}
+	if h.Type, newOff, err = unpackType(msg, newOff); err != nil {
+		return off, &nestedError{"Type", err}
+	}
+	if h.Class, newOff, err = unpackClass(msg, newOff); err != nil {
+		return off, &nestedError{"Class", err}
+	}
+	if h.TTL, newOff, err = unpackUint32(msg, newOff); err != nil {
+		return off, &nestedError{"TTL", err}
+	}
+	if h.Length, newOff, err = unpackUint16(msg, newOff); err != nil {
+		return off, &nestedError{"Length", err}
+	}
+	return newOff, nil
+}
+
+func (h *ResourceHeader) fixLen(msg []byte, length []byte, preLen int) error {
+	conLen := len(msg) - preLen
+	if conLen > int(^uint16(0)) {
+		return errResTooLong
+	}
+
+	// Fill in the length now that we know how long the content is.
+	packUint16(length[:0], uint16(conLen))
+	h.Length = uint16(conLen)
+
+	return nil
+}
+
+func skipResource(msg []byte, off int) (int, error) {
+	newOff, err := skipName(msg, off)
+	if err != nil {
+		return off, &nestedError{"Name", err}
+	}
+	if newOff, err = skipType(msg, newOff); err != nil {
+		return off, &nestedError{"Type", err}
+	}
+	if newOff, err = skipClass(msg, newOff); err != nil {
+		return off, &nestedError{"Class", err}
+	}
+	if newOff, err = skipUint32(msg, newOff); err != nil {
+		return off, &nestedError{"TTL", err}
+	}
+	length, newOff, err := unpackUint16(msg, newOff)
+	if err != nil {
+		return off, &nestedError{"Length", err}
+	}
+	if newOff += int(length); newOff > len(msg) {
+		return off, errResourceLen
+	}
+	return newOff, nil
+}
+
+func packUint16(msg []byte, field uint16) []byte {
+	return append(msg, byte(field>>8), byte(field))
+}
+
+func unpackUint16(msg []byte, off int) (uint16, int, error) {
+	if off+uint16Len > len(msg) {
+		return 0, off, errBaseLen
+	}
+	return uint16(msg[off])<<8 | uint16(msg[off+1]), off + uint16Len, nil
+}
+
+func skipUint16(msg []byte, off int) (int, error) {
+	if off+uint16Len > len(msg) {
+		return off, errBaseLen
+	}
+	return off + uint16Len, nil
+}
+
+func packType(msg []byte, field Type) []byte {
+	return packUint16(msg, uint16(field))
+}
+
+func unpackType(msg []byte, off int) (Type, int, error) {
+	t, o, err := unpackUint16(msg, off)
+	return Type(t), o, err
+}
+
+func skipType(msg []byte, off int) (int, error) {
+	return skipUint16(msg, off)
+}
+
+func packClass(msg []byte, field Class) []byte {
+	return packUint16(msg, uint16(field))
+}
+
+func unpackClass(msg []byte, off int) (Class, int, error) {
+	c, o, err := unpackUint16(msg, off)
+	return Class(c), o, err
+}
+
+func skipClass(msg []byte, off int) (int, error) {
+	return skipUint16(msg, off)
+}
+
+func packUint32(msg []byte, field uint32) []byte {
+	return append(
+		msg,
+		byte(field>>24),
+		byte(field>>16),
+		byte(field>>8),
+		byte(field),
+	)
+}
+
+func unpackUint32(msg []byte, off int) (uint32, int, error) {
+	if off+uint32Len > len(msg) {
+		return 0, off, errBaseLen
+	}
+	v := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
+	return v, off + uint32Len, nil
+}
+
+func skipUint32(msg []byte, off int) (int, error) {
+	if off+uint32Len > len(msg) {
+		return off, errBaseLen
+	}
+	return off + uint32Len, nil
+}
+
+func packText(msg []byte, field string) []byte {
+	for len(field) > 0 {
+		l := len(field)
+		if l > 255 {
+			l = 255
+		}
+		msg = append(msg, byte(l))
+		msg = append(msg, field[:l]...)
+		field = field[l:]
+	}
+	return msg
+}
+
+func unpackText(msg []byte, off int) (string, int, error) {
+	if off >= len(msg) {
+		return "", off, errBaseLen
+	}
+	beginOff := off + 1
+	endOff := beginOff + int(msg[off])
+	if endOff > len(msg) {
+		return "", off, errCalcLen
+	}
+	return string(msg[beginOff:endOff]), endOff, nil
+}
+
+func skipText(msg []byte, off int) (int, error) {
+	if off >= len(msg) {
+		return off, errBaseLen
+	}
+	endOff := off + 1 + int(msg[off])
+	if endOff > len(msg) {
+		return off, errCalcLen
+	}
+	return endOff, nil
+}
+
+func packBytes(msg []byte, field []byte) []byte {
+	return append(msg, field...)
+}
+
+func unpackBytes(msg []byte, off int, field []byte) (int, error) {
+	newOff := off + len(field)
+	if newOff > len(msg) {
+		return off, errBaseLen
+	}
+	copy(field, msg[off:newOff])
+	return newOff, nil
+}
+
+func skipBytes(msg []byte, off int, field []byte) (int, error) {
+	newOff := off + len(field)
+	if newOff > len(msg) {
+		return off, errBaseLen
+	}
+	return newOff, nil
+}
+
+const nameLen = 255
+
+// A Name is a non-encoded domain name. It is used instead of strings to avoid
+// allocations.
+type Name struct {
+	Data   [nameLen]byte
+	Length uint8
+}
+
+// NewName creates a new Name from a string.
+func NewName(name string) (Name, error) {
+	if len([]byte(name)) > nameLen {
+		return Name{}, errCalcLen
+	}
+	n := Name{Length: uint8(len(name))}
+	copy(n.Data[:], []byte(name))
+	return n, nil
+}
+
+func (n Name) String() string {
+	return string(n.Data[:n.Length])
+}
+
+// pack packs a domain name.
+//
+// Domain names are a sequence of counted strings split at the dots. They end
+// with a zero-length string. Compression can be used to reuse domain suffixes.
+//
+// The compression map will be updated with new domain suffixes. If compression
+// is nil, compression will not be used.
+func (n *Name) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	oldMsg := msg
+
+	// Add a trailing dot to canonicalize name.
+	if n.Length == 0 || n.Data[n.Length-1] != '.' {
+		return oldMsg, errNonCanonicalName
+	}
+
+	// Allow root domain.
+	if n.Data[0] == '.' && n.Length == 1 {
+		return append(msg, 0), nil
+	}
+
+	// Emit sequence of counted strings, chopping at dots.
+	for i, begin := 0, 0; i < int(n.Length); i++ {
+		// Check for the end of the segment.
+		if n.Data[i] == '.' {
+			// The two most significant bits have special meaning.
+			// It isn't allowed for segments to be long enough to
+			// need them.
+			if i-begin >= 1<<6 {
+				return oldMsg, errSegTooLong
+			}
+
+			// Segments must have a non-zero length.
+			if i-begin == 0 {
+				return oldMsg, errZeroSegLen
+			}
+
+			msg = append(msg, byte(i-begin))
+
+			for j := begin; j < i; j++ {
+				msg = append(msg, n.Data[j])
+			}
+
+			begin = i + 1
+			continue
+		}
+
+		// We can only compress domain suffixes starting with a new
+		// segment. A pointer is two bytes with the two most significant
+		// bits set to 1 to indicate that it is a pointer.
+		if (i == 0 || n.Data[i-1] == '.') && compression != nil {
+			if ptr, ok := compression[string(n.Data[i:])]; ok {
+				// Hit. Emit a pointer instead of the rest of
+				// the domain.
+				return append(msg, byte(ptr>>8|0xC0), byte(ptr)), nil
+			}
+
+			// Miss. Add the suffix to the compression table if the
+			// offset can be stored in the available 14 bytes.
+			if len(msg) <= int(^uint16(0)>>2) {
+				compression[string(n.Data[i:])] = len(msg)
+			}
+		}
+	}
+	return append(msg, 0), nil
+}
+
+// unpack unpacks a domain name.
+func (n *Name) unpack(msg []byte, off int) (int, error) {
+	// currOff is the current working offset.
+	currOff := off
+
+	// newOff is the offset where the next record will start. Pointers lead
+	// to data that belongs to other names and thus doesn't count towards to
+	// the usage of this name.
+	newOff := off
+
+	// ptr is the number of pointers followed.
+	var ptr int
+
+	// Name is a slice representation of the name data.
+	name := n.Data[:0]
+
+Loop:
+	for {
+		if currOff >= len(msg) {
+			return off, errBaseLen
+		}
+		c := int(msg[currOff])
+		currOff++
+		switch c & 0xC0 {
+		case 0x00: // String segment
+			if c == 0x00 {
+				// A zero length signals the end of the name.
+				break Loop
+			}
+			endOff := currOff + c
+			if endOff > len(msg) {
+				return off, errCalcLen
+			}
+			name = append(name, msg[currOff:endOff]...)
+			name = append(name, '.')
+			currOff = endOff
+		case 0xC0: // Pointer
+			if currOff >= len(msg) {
+				return off, errInvalidPtr
+			}
+			c1 := msg[currOff]
+			currOff++
+			if ptr == 0 {
+				newOff = currOff
+			}
+			// Don't follow too many pointers, maybe there's a loop.
+			if ptr++; ptr > 10 {
+				return off, errTooManyPtr
+			}
+			currOff = (c^0xC0)<<8 | int(c1)
+		default:
+			// Prefixes 0x80 and 0x40 are reserved.
+			return off, errReserved
+		}
+	}
+	if len(name) == 0 {
+		name = append(name, '.')
+	}
+	if len(name) > len(n.Data) {
+		return off, errCalcLen
+	}
+	n.Length = uint8(len(name))
+	if ptr == 0 {
+		newOff = currOff
+	}
+	return newOff, nil
+}
+
+func skipName(msg []byte, off int) (int, error) {
+	// newOff is the offset where the next record will start. Pointers lead
+	// to data that belongs to other names and thus doesn't count towards to
+	// the usage of this name.
+	newOff := off
+
+Loop:
+	for {
+		if newOff >= len(msg) {
+			return off, errBaseLen
+		}
+		c := int(msg[newOff])
+		newOff++
+		switch c & 0xC0 {
+		case 0x00:
+			if c == 0x00 {
+				// A zero length signals the end of the name.
+				break Loop
+			}
+			// literal string
+			newOff += c
+			if newOff > len(msg) {
+				return off, errCalcLen
+			}
+		case 0xC0:
+			// Pointer to somewhere else in msg.
+
+			// Pointers are two bytes.
+			newOff++
+
+			// Don't follow the pointer as the data here has ended.
+			break Loop
+		default:
+			// Prefixes 0x80 and 0x40 are reserved.
+			return off, errReserved
+		}
+	}
+
+	return newOff, nil
+}
+
+// A Question is a DNS query.
+type Question struct {
+	Name  Name
+	Type  Type
+	Class Class
+}
+
+func (q *Question) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	msg, err := q.Name.pack(msg, compression)
+	if err != nil {
+		return msg, &nestedError{"Name", err}
+	}
+	msg = packType(msg, q.Type)
+	return packClass(msg, q.Class), nil
+}
+
+func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, int, error) {
+	var (
+		r    ResourceBody
+		err  error
+		name string
+	)
+	switch hdr.Type {
+	case TypeA:
+		var rb AResource
+		rb, err = unpackAResource(msg, off)
+		r = &rb
+		name = "A"
+	case TypeNS:
+		var rb NSResource
+		rb, err = unpackNSResource(msg, off)
+		r = &rb
+		name = "NS"
+	case TypeCNAME:
+		var rb CNAMEResource
+		rb, err = unpackCNAMEResource(msg, off)
+		r = &rb
+		name = "CNAME"
+	case TypeSOA:
+		var rb SOAResource
+		rb, err = unpackSOAResource(msg, off)
+		r = &rb
+		name = "SOA"
+	case TypePTR:
+		var rb PTRResource
+		rb, err = unpackPTRResource(msg, off)
+		r = &rb
+		name = "PTR"
+	case TypeMX:
+		var rb MXResource
+		rb, err = unpackMXResource(msg, off)
+		r = &rb
+		name = "MX"
+	case TypeTXT:
+		var rb TXTResource
+		rb, err = unpackTXTResource(msg, off, hdr.Length)
+		r = &rb
+		name = "TXT"
+	case TypeAAAA:
+		var rb AAAAResource
+		rb, err = unpackAAAAResource(msg, off)
+		r = &rb
+		name = "AAAA"
+	case TypeSRV:
+		var rb SRVResource
+		rb, err = unpackSRVResource(msg, off)
+		r = &rb
+		name = "SRV"
+	}
+	if err != nil {
+		return nil, off, &nestedError{name + " record", err}
+	}
+	if r == nil {
+		return nil, off, errors.New("invalid resource type: " + string(hdr.Type+'0'))
+	}
+	return r, off + int(hdr.Length), nil
+}
+
+// A CNAMEResource is a CNAME Resource record.
+type CNAMEResource struct {
+	CNAME Name
+}
+
+func (r *CNAMEResource) realType() Type {
+	return TypeCNAME
+}
+
+func (r *CNAMEResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	return r.CNAME.pack(msg, compression)
+}
+
+func unpackCNAMEResource(msg []byte, off int) (CNAMEResource, error) {
+	var cname Name
+	if _, err := cname.unpack(msg, off); err != nil {
+		return CNAMEResource{}, err
+	}
+	return CNAMEResource{cname}, nil
+}
+
+// An MXResource is an MX Resource record.
+type MXResource struct {
+	Pref uint16
+	MX   Name
+}
+
+func (r *MXResource) realType() Type {
+	return TypeMX
+}
+
+func (r *MXResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	oldMsg := msg
+	msg = packUint16(msg, r.Pref)
+	msg, err := r.MX.pack(msg, compression)
+	if err != nil {
+		return oldMsg, &nestedError{"MXResource.MX", err}
+	}
+	return msg, nil
+}
+
+func unpackMXResource(msg []byte, off int) (MXResource, error) {
+	pref, off, err := unpackUint16(msg, off)
+	if err != nil {
+		return MXResource{}, &nestedError{"Pref", err}
+	}
+	var mx Name
+	if _, err := mx.unpack(msg, off); err != nil {
+		return MXResource{}, &nestedError{"MX", err}
+	}
+	return MXResource{pref, mx}, nil
+}
+
+// An NSResource is an NS Resource record.
+type NSResource struct {
+	NS Name
+}
+
+func (r *NSResource) realType() Type {
+	return TypeNS
+}
+
+func (r *NSResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	return r.NS.pack(msg, compression)
+}
+
+func unpackNSResource(msg []byte, off int) (NSResource, error) {
+	var ns Name
+	if _, err := ns.unpack(msg, off); err != nil {
+		return NSResource{}, err
+	}
+	return NSResource{ns}, nil
+}
+
+// A PTRResource is a PTR Resource record.
+type PTRResource struct {
+	PTR Name
+}
+
+func (r *PTRResource) realType() Type {
+	return TypePTR
+}
+
+func (r *PTRResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	return r.PTR.pack(msg, compression)
+}
+
+func unpackPTRResource(msg []byte, off int) (PTRResource, error) {
+	var ptr Name
+	if _, err := ptr.unpack(msg, off); err != nil {
+		return PTRResource{}, err
+	}
+	return PTRResource{ptr}, nil
+}
+
+// An SOAResource is an SOA Resource record.
+type SOAResource struct {
+	NS      Name
+	MBox    Name
+	Serial  uint32
+	Refresh uint32
+	Retry   uint32
+	Expire  uint32
+
+	// MinTTL the is the default TTL of Resources records which did not
+	// contain a TTL value and the TTL of negative responses. (RFC 2308
+	// Section 4)
+	MinTTL uint32
+}
+
+func (r *SOAResource) realType() Type {
+	return TypeSOA
+}
+
+func (r *SOAResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	oldMsg := msg
+	msg, err := r.NS.pack(msg, compression)
+	if err != nil {
+		return oldMsg, &nestedError{"SOAResource.NS", err}
+	}
+	msg, err = r.MBox.pack(msg, compression)
+	if err != nil {
+		return oldMsg, &nestedError{"SOAResource.MBox", err}
+	}
+	msg = packUint32(msg, r.Serial)
+	msg = packUint32(msg, r.Refresh)
+	msg = packUint32(msg, r.Retry)
+	msg = packUint32(msg, r.Expire)
+	return packUint32(msg, r.MinTTL), nil
+}
+
+func unpackSOAResource(msg []byte, off int) (SOAResource, error) {
+	var ns Name
+	off, err := ns.unpack(msg, off)
+	if err != nil {
+		return SOAResource{}, &nestedError{"NS", err}
+	}
+	var mbox Name
+	if off, err = mbox.unpack(msg, off); err != nil {
+		return SOAResource{}, &nestedError{"MBox", err}
+	}
+	serial, off, err := unpackUint32(msg, off)
+	if err != nil {
+		return SOAResource{}, &nestedError{"Serial", err}
+	}
+	refresh, off, err := unpackUint32(msg, off)
+	if err != nil {
+		return SOAResource{}, &nestedError{"Refresh", err}
+	}
+	retry, off, err := unpackUint32(msg, off)
+	if err != nil {
+		return SOAResource{}, &nestedError{"Retry", err}
+	}
+	expire, off, err := unpackUint32(msg, off)
+	if err != nil {
+		return SOAResource{}, &nestedError{"Expire", err}
+	}
+	minTTL, _, err := unpackUint32(msg, off)
+	if err != nil {
+		return SOAResource{}, &nestedError{"MinTTL", err}
+	}
+	return SOAResource{ns, mbox, serial, refresh, retry, expire, minTTL}, nil
+}
+
+// A TXTResource is a TXT Resource record.
+type TXTResource struct {
+	Txt string // Not a domain name.
+}
+
+func (r *TXTResource) realType() Type {
+	return TypeTXT
+}
+
+func (r *TXTResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	return packText(msg, r.Txt), nil
+}
+
+func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) {
+	var txt string
+	for n := uint16(0); n < length; {
+		var t string
+		var err error
+		if t, off, err = unpackText(msg, off); err != nil {
+			return TXTResource{}, &nestedError{"text", err}
+		}
+		// Check if we got too many bytes.
+		if length-n < uint16(len(t))+1 {
+			return TXTResource{}, errCalcLen
+		}
+		n += uint16(len(t)) + 1
+		txt += t
+	}
+	return TXTResource{txt}, nil
+}
+
+// An SRVResource is an SRV Resource record.
+type SRVResource struct {
+	Priority uint16
+	Weight   uint16
+	Port     uint16
+	Target   Name // Not compressed as per RFC 2782.
+}
+
+func (r *SRVResource) realType() Type {
+	return TypeSRV
+}
+
+func (r *SRVResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	oldMsg := msg
+	msg = packUint16(msg, r.Priority)
+	msg = packUint16(msg, r.Weight)
+	msg = packUint16(msg, r.Port)
+	msg, err := r.Target.pack(msg, nil)
+	if err != nil {
+		return oldMsg, &nestedError{"SRVResource.Target", err}
+	}
+	return msg, nil
+}
+
+func unpackSRVResource(msg []byte, off int) (SRVResource, error) {
+	priority, off, err := unpackUint16(msg, off)
+	if err != nil {
+		return SRVResource{}, &nestedError{"Priority", err}
+	}
+	weight, off, err := unpackUint16(msg, off)
+	if err != nil {
+		return SRVResource{}, &nestedError{"Weight", err}
+	}
+	port, off, err := unpackUint16(msg, off)
+	if err != nil {
+		return SRVResource{}, &nestedError{"Port", err}
+	}
+	var target Name
+	if _, err := target.unpack(msg, off); err != nil {
+		return SRVResource{}, &nestedError{"Target", err}
+	}
+	return SRVResource{priority, weight, port, target}, nil
+}
+
+// An AResource is an A Resource record.
+type AResource struct {
+	A [4]byte
+}
+
+func (r *AResource) realType() Type {
+	return TypeA
+}
+
+func (r *AResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	return packBytes(msg, r.A[:]), nil
+}
+
+func unpackAResource(msg []byte, off int) (AResource, error) {
+	var a [4]byte
+	if _, err := unpackBytes(msg, off, a[:]); err != nil {
+		return AResource{}, err
+	}
+	return AResource{a}, nil
+}
+
+// An AAAAResource is an AAAA Resource record.
+type AAAAResource struct {
+	AAAA [16]byte
+}
+
+func (r *AAAAResource) realType() Type {
+	return TypeAAAA
+}
+
+func (r *AAAAResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
+	return packBytes(msg, r.AAAA[:]), nil
+}
+
+func unpackAAAAResource(msg []byte, off int) (AAAAResource, error) {
+	var aaaa [16]byte
+	if _, err := unpackBytes(msg, off, aaaa[:]); err != nil {
+		return AAAAResource{}, err
+	}
+	return AAAAResource{aaaa}, nil
+}

+ 1116 - 0
vendor/golang.org/x/net/dns/dnsmessage/message_test.go

@@ -0,0 +1,1116 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dnsmessage
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+func mustNewName(name string) Name {
+	n, err := NewName(name)
+	if err != nil {
+		panic(err)
+	}
+	return n
+}
+
+func (m *Message) String() string {
+	s := fmt.Sprintf("Message: %#v\n", &m.Header)
+	if len(m.Questions) > 0 {
+		s += "-- Questions\n"
+		for _, q := range m.Questions {
+			s += fmt.Sprintf("%#v\n", q)
+		}
+	}
+	if len(m.Answers) > 0 {
+		s += "-- Answers\n"
+		for _, a := range m.Answers {
+			s += fmt.Sprintf("%#v\n", a)
+		}
+	}
+	if len(m.Authorities) > 0 {
+		s += "-- Authorities\n"
+		for _, ns := range m.Authorities {
+			s += fmt.Sprintf("%#v\n", ns)
+		}
+	}
+	if len(m.Additionals) > 0 {
+		s += "-- Additionals\n"
+		for _, e := range m.Additionals {
+			s += fmt.Sprintf("%#v\n", e)
+		}
+	}
+	return s
+}
+
+func TestNameString(t *testing.T) {
+	want := "foo"
+	name := mustNewName(want)
+	if got := fmt.Sprint(name); got != want {
+		t.Errorf("got fmt.Sprint(%#v) = %s, want = %s", name, got, want)
+	}
+}
+
+func TestQuestionPackUnpack(t *testing.T) {
+	want := Question{
+		Name:  mustNewName("."),
+		Type:  TypeA,
+		Class: ClassINET,
+	}
+	buf, err := want.pack(make([]byte, 1, 50), map[string]int{})
+	if err != nil {
+		t.Fatal("Packing failed:", err)
+	}
+	var p Parser
+	p.msg = buf
+	p.header.questions = 1
+	p.section = sectionQuestions
+	p.off = 1
+	got, err := p.Question()
+	if err != nil {
+		t.Fatalf("Unpacking failed: %v\n%s", err, string(buf[1:]))
+	}
+	if p.off != len(buf) {
+		t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", p.off, len(buf))
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Got = %+v, want = %+v", got, want)
+	}
+}
+
+func TestName(t *testing.T) {
+	tests := []string{
+		"",
+		".",
+		"google..com",
+		"google.com",
+		"google..com.",
+		"google.com.",
+		".google.com.",
+		"www..google.com.",
+		"www.google.com.",
+	}
+
+	for _, test := range tests {
+		n, err := NewName(test)
+		if err != nil {
+			t.Errorf("Creating name for %q: %v", test, err)
+			continue
+		}
+		if ns := n.String(); ns != test {
+			t.Errorf("Got %#v.String() = %q, want = %q", n, ns, test)
+			continue
+		}
+	}
+}
+
+func TestNamePackUnpack(t *testing.T) {
+	tests := []struct {
+		in   string
+		want string
+		err  error
+	}{
+		{"", "", errNonCanonicalName},
+		{".", ".", nil},
+		{"google..com", "", errNonCanonicalName},
+		{"google.com", "", errNonCanonicalName},
+		{"google..com.", "", errZeroSegLen},
+		{"google.com.", "google.com.", nil},
+		{".google.com.", "", errZeroSegLen},
+		{"www..google.com.", "", errZeroSegLen},
+		{"www.google.com.", "www.google.com.", nil},
+	}
+
+	for _, test := range tests {
+		in := mustNewName(test.in)
+		want := mustNewName(test.want)
+		buf, err := in.pack(make([]byte, 0, 30), map[string]int{})
+		if err != test.err {
+			t.Errorf("Packing of %q: got err = %v, want err = %v", test.in, err, test.err)
+			continue
+		}
+		if test.err != nil {
+			continue
+		}
+		var got Name
+		n, err := got.unpack(buf, 0)
+		if err != nil {
+			t.Errorf("Unpacking for %q failed: %v", test.in, err)
+			continue
+		}
+		if n != len(buf) {
+			t.Errorf(
+				"Unpacked different amount than packed for %q: got n = %d, want = %d",
+				test.in,
+				n,
+				len(buf),
+			)
+		}
+		if got != want {
+			t.Errorf("Unpacking packing of %q: got = %#v, want = %#v", test.in, got, want)
+		}
+	}
+}
+
+func checkErrorPrefix(err error, prefix string) bool {
+	e, ok := err.(*nestedError)
+	return ok && e.s == prefix
+}
+
+func TestHeaderUnpackError(t *testing.T) {
+	wants := []string{
+		"id",
+		"bits",
+		"questions",
+		"answers",
+		"authorities",
+		"additionals",
+	}
+	var buf []byte
+	var h header
+	for _, want := range wants {
+		n, err := h.unpack(buf, 0)
+		if n != 0 || !checkErrorPrefix(err, want) {
+			t.Errorf("got h.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want)
+		}
+		buf = append(buf, 0, 0)
+	}
+}
+
+func TestParserStart(t *testing.T) {
+	const want = "unpacking header"
+	var p Parser
+	for i := 0; i <= 1; i++ {
+		_, err := p.Start([]byte{})
+		if !checkErrorPrefix(err, want) {
+			t.Errorf("got p.Start(nil) = _, %v, want = _, %s", err, want)
+		}
+	}
+}
+
+func TestResourceNotStarted(t *testing.T) {
+	tests := []struct {
+		name string
+		fn   func(*Parser) error
+	}{
+		{"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }},
+		{"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }},
+		{"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }},
+		{"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }},
+		{"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }},
+		{"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }},
+		{"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }},
+		{"AResource", func(p *Parser) error { _, err := p.AResource(); return err }},
+		{"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }},
+	}
+
+	for _, test := range tests {
+		if err := test.fn(&Parser{}); err != ErrNotStarted {
+			t.Errorf("got _, %v = p.%s(), want = _, %v", err, test.name, ErrNotStarted)
+		}
+	}
+}
+
+func TestDNSPackUnpack(t *testing.T) {
+	wants := []Message{
+		{
+			Questions: []Question{
+				{
+					Name:  mustNewName("."),
+					Type:  TypeAAAA,
+					Class: ClassINET,
+				},
+			},
+			Answers:     []Resource{},
+			Authorities: []Resource{},
+			Additionals: []Resource{},
+		},
+		largeTestMsg(),
+	}
+	for i, want := range wants {
+		b, err := want.Pack()
+		if err != nil {
+			t.Fatalf("%d: packing failed: %v", i, err)
+		}
+		var got Message
+		err = got.Unpack(b)
+		if err != nil {
+			t.Fatalf("%d: unpacking failed: %v", i, err)
+		}
+		if !reflect.DeepEqual(got, want) {
+			t.Errorf("%d: got = %+v, want = %+v", i, &got, &want)
+		}
+	}
+}
+
+func TestSkipAll(t *testing.T) {
+	msg := largeTestMsg()
+	buf, err := msg.Pack()
+	if err != nil {
+		t.Fatal("Packing large test message:", err)
+	}
+	var p Parser
+	if _, err := p.Start(buf); err != nil {
+		t.Fatal(err)
+	}
+
+	tests := []struct {
+		name string
+		f    func() error
+	}{
+		{"SkipAllQuestions", p.SkipAllQuestions},
+		{"SkipAllAnswers", p.SkipAllAnswers},
+		{"SkipAllAuthorities", p.SkipAllAuthorities},
+		{"SkipAllAdditionals", p.SkipAllAdditionals},
+	}
+	for _, test := range tests {
+		for i := 1; i <= 3; i++ {
+			if err := test.f(); err != nil {
+				t.Errorf("Call #%d to %s(): %v", i, test.name, err)
+			}
+		}
+	}
+}
+
+func TestSkipEach(t *testing.T) {
+	msg := smallTestMsg()
+
+	buf, err := msg.Pack()
+	if err != nil {
+		t.Fatal("Packing test message:", err)
+	}
+	var p Parser
+	if _, err := p.Start(buf); err != nil {
+		t.Fatal(err)
+	}
+
+	tests := []struct {
+		name string
+		f    func() error
+	}{
+		{"SkipQuestion", p.SkipQuestion},
+		{"SkipAnswer", p.SkipAnswer},
+		{"SkipAuthority", p.SkipAuthority},
+		{"SkipAdditional", p.SkipAdditional},
+	}
+	for _, test := range tests {
+		if err := test.f(); err != nil {
+			t.Errorf("First call: got %s() = %v, want = %v", test.name, err, nil)
+		}
+		if err := test.f(); err != ErrSectionDone {
+			t.Errorf("Second call: got %s() = %v, want = %v", test.name, err, ErrSectionDone)
+		}
+	}
+}
+
+func TestSkipAfterRead(t *testing.T) {
+	msg := smallTestMsg()
+
+	buf, err := msg.Pack()
+	if err != nil {
+		t.Fatal("Packing test message:", err)
+	}
+	var p Parser
+	if _, err := p.Start(buf); err != nil {
+		t.Fatal(err)
+	}
+
+	tests := []struct {
+		name string
+		skip func() error
+		read func() error
+	}{
+		{"Question", p.SkipQuestion, func() error { _, err := p.Question(); return err }},
+		{"Answer", p.SkipAnswer, func() error { _, err := p.Answer(); return err }},
+		{"Authority", p.SkipAuthority, func() error { _, err := p.Authority(); return err }},
+		{"Additional", p.SkipAdditional, func() error { _, err := p.Additional(); return err }},
+	}
+	for _, test := range tests {
+		if err := test.read(); err != nil {
+			t.Errorf("Got %s() = _, %v, want = _, %v", test.name, err, nil)
+		}
+		if err := test.skip(); err != ErrSectionDone {
+			t.Errorf("Got Skip%s() = %v, want = %v", test.name, err, ErrSectionDone)
+		}
+	}
+}
+
+func TestSkipNotStarted(t *testing.T) {
+	var p Parser
+
+	tests := []struct {
+		name string
+		f    func() error
+	}{
+		{"SkipAllQuestions", p.SkipAllQuestions},
+		{"SkipAllAnswers", p.SkipAllAnswers},
+		{"SkipAllAuthorities", p.SkipAllAuthorities},
+		{"SkipAllAdditionals", p.SkipAllAdditionals},
+	}
+	for _, test := range tests {
+		if err := test.f(); err != ErrNotStarted {
+			t.Errorf("Got %s() = %v, want = %v", test.name, err, ErrNotStarted)
+		}
+	}
+}
+
+func TestTooManyRecords(t *testing.T) {
+	const recs = int(^uint16(0)) + 1
+	tests := []struct {
+		name string
+		msg  Message
+		want error
+	}{
+		{
+			"Questions",
+			Message{
+				Questions: make([]Question, recs),
+			},
+			errTooManyQuestions,
+		},
+		{
+			"Answers",
+			Message{
+				Answers: make([]Resource, recs),
+			},
+			errTooManyAnswers,
+		},
+		{
+			"Authorities",
+			Message{
+				Authorities: make([]Resource, recs),
+			},
+			errTooManyAuthorities,
+		},
+		{
+			"Additionals",
+			Message{
+				Additionals: make([]Resource, recs),
+			},
+			errTooManyAdditionals,
+		},
+	}
+
+	for _, test := range tests {
+		if _, got := test.msg.Pack(); got != test.want {
+			t.Errorf("Packing %d %s: got = %v, want = %v", recs, test.name, got, test.want)
+		}
+	}
+}
+
+func TestVeryLongTxt(t *testing.T) {
+	want := Resource{
+		ResourceHeader{
+			Name:  mustNewName("foo.bar.example.com."),
+			Type:  TypeTXT,
+			Class: ClassINET,
+		},
+		&TXTResource{loremIpsum},
+	}
+	buf, err := want.pack(make([]byte, 0, 8000), map[string]int{})
+	if err != nil {
+		t.Fatal("Packing failed:", err)
+	}
+	var got Resource
+	off, err := got.Header.unpack(buf, 0)
+	if err != nil {
+		t.Fatal("Unpacking ResourceHeader failed:", err)
+	}
+	body, n, err := unpackResourceBody(buf, off, got.Header)
+	if err != nil {
+		t.Fatal("Unpacking failed:", err)
+	}
+	got.Body = body
+	if n != len(buf) {
+		t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", n, len(buf))
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Got = %#v, want = %#v", got, want)
+	}
+}
+
+func TestStartError(t *testing.T) {
+	tests := []struct {
+		name string
+		fn   func(*Builder) error
+	}{
+		{"Questions", func(b *Builder) error { return b.StartQuestions() }},
+		{"Answers", func(b *Builder) error { return b.StartAnswers() }},
+		{"Authorities", func(b *Builder) error { return b.StartAuthorities() }},
+		{"Additionals", func(b *Builder) error { return b.StartAdditionals() }},
+	}
+
+	envs := []struct {
+		name string
+		fn   func() *Builder
+		want error
+	}{
+		{"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
+		{"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
+	}
+
+	for _, env := range envs {
+		for _, test := range tests {
+			if got := test.fn(env.fn()); got != env.want {
+				t.Errorf("got Builder{%s}.Start%s = %v, want = %v", env.name, test.name, got, env.want)
+			}
+		}
+	}
+}
+
+func TestBuilderResourceError(t *testing.T) {
+	tests := []struct {
+		name string
+		fn   func(*Builder) error
+	}{
+		{"CNAMEResource", func(b *Builder) error { return b.CNAMEResource(ResourceHeader{}, CNAMEResource{}) }},
+		{"MXResource", func(b *Builder) error { return b.MXResource(ResourceHeader{}, MXResource{}) }},
+		{"NSResource", func(b *Builder) error { return b.NSResource(ResourceHeader{}, NSResource{}) }},
+		{"PTRResource", func(b *Builder) error { return b.PTRResource(ResourceHeader{}, PTRResource{}) }},
+		{"SOAResource", func(b *Builder) error { return b.SOAResource(ResourceHeader{}, SOAResource{}) }},
+		{"TXTResource", func(b *Builder) error { return b.TXTResource(ResourceHeader{}, TXTResource{}) }},
+		{"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }},
+		{"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }},
+		{"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }},
+	}
+
+	envs := []struct {
+		name string
+		fn   func() *Builder
+		want error
+	}{
+		{"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
+		{"sectionHeader", func() *Builder { return &Builder{section: sectionHeader} }, ErrNotStarted},
+		{"sectionQuestions", func() *Builder { return &Builder{section: sectionQuestions} }, ErrNotStarted},
+		{"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
+	}
+
+	for _, env := range envs {
+		for _, test := range tests {
+			if got := test.fn(env.fn()); got != env.want {
+				t.Errorf("got Builder{%s}.%s = %v, want = %v", env.name, test.name, got, env.want)
+			}
+		}
+	}
+}
+
+func TestFinishError(t *testing.T) {
+	var b Builder
+	want := ErrNotStarted
+	if _, got := b.Finish(); got != want {
+		t.Errorf("got Builder{}.Finish() = %v, want = %v", got, want)
+	}
+}
+
+func TestBuilder(t *testing.T) {
+	msg := largeTestMsg()
+	want, err := msg.Pack()
+	if err != nil {
+		t.Fatal("Packing without builder:", err)
+	}
+
+	var b Builder
+	b.Start(nil, msg.Header)
+
+	if err := b.StartQuestions(); err != nil {
+		t.Fatal("b.StartQuestions():", err)
+	}
+	for _, q := range msg.Questions {
+		if err := b.Question(q); err != nil {
+			t.Fatalf("b.Question(%#v): %v", q, err)
+		}
+	}
+
+	if err := b.StartAnswers(); err != nil {
+		t.Fatal("b.StartAnswers():", err)
+	}
+	for _, a := range msg.Answers {
+		switch a.Header.Type {
+		case TypeA:
+			if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil {
+				t.Fatalf("b.AResource(%#v): %v", a, err)
+			}
+		case TypeNS:
+			if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
+				t.Fatalf("b.NSResource(%#v): %v", a, err)
+			}
+		case TypeCNAME:
+			if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil {
+				t.Fatalf("b.CNAMEResource(%#v): %v", a, err)
+			}
+		case TypeSOA:
+			if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil {
+				t.Fatalf("b.SOAResource(%#v): %v", a, err)
+			}
+		case TypePTR:
+			if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil {
+				t.Fatalf("b.PTRResource(%#v): %v", a, err)
+			}
+		case TypeMX:
+			if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil {
+				t.Fatalf("b.MXResource(%#v): %v", a, err)
+			}
+		case TypeTXT:
+			if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
+				t.Fatalf("b.TXTResource(%#v): %v", a, err)
+			}
+		case TypeAAAA:
+			if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil {
+				t.Fatalf("b.AAAAResource(%#v): %v", a, err)
+			}
+		case TypeSRV:
+			if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil {
+				t.Fatalf("b.SRVResource(%#v): %v", a, err)
+			}
+		}
+	}
+
+	if err := b.StartAuthorities(); err != nil {
+		t.Fatal("b.StartAuthorities():", err)
+	}
+	for _, a := range msg.Authorities {
+		if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
+			t.Fatalf("b.NSResource(%#v): %v", a, err)
+		}
+	}
+
+	if err := b.StartAdditionals(); err != nil {
+		t.Fatal("b.StartAdditionals():", err)
+	}
+	for _, a := range msg.Additionals {
+		if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
+			t.Fatalf("b.TXTResource(%#v): %v", a, err)
+		}
+	}
+
+	got, err := b.Finish()
+	if err != nil {
+		t.Fatal("b.Finish():", err)
+	}
+	if !bytes.Equal(got, want) {
+		t.Fatalf("Got from Builder: %#v\nwant = %#v", got, want)
+	}
+}
+
+func TestResourcePack(t *testing.T) {
+	for _, tt := range []struct {
+		m   Message
+		err error
+	}{
+		{
+			Message{
+				Questions: []Question{
+					{
+						Name:  mustNewName("."),
+						Type:  TypeAAAA,
+						Class: ClassINET,
+					},
+				},
+				Answers: []Resource{{ResourceHeader{}, nil}},
+			},
+			&nestedError{"packing Answer", errNilResouceBody},
+		},
+		{
+			Message{
+				Questions: []Question{
+					{
+						Name:  mustNewName("."),
+						Type:  TypeAAAA,
+						Class: ClassINET,
+					},
+				},
+				Authorities: []Resource{{ResourceHeader{}, (*NSResource)(nil)}},
+			},
+			&nestedError{"packing Authority",
+				&nestedError{"ResourceHeader",
+					&nestedError{"Name", errNonCanonicalName},
+				},
+			},
+		},
+		{
+			Message{
+				Questions: []Question{
+					{
+						Name:  mustNewName("."),
+						Type:  TypeA,
+						Class: ClassINET,
+					},
+				},
+				Additionals: []Resource{{ResourceHeader{}, nil}},
+			},
+			&nestedError{"packing Additional", errNilResouceBody},
+		},
+	} {
+		_, err := tt.m.Pack()
+		if !reflect.DeepEqual(err, tt.err) {
+			t.Errorf("got %v for %v; want %v", err, tt.m, tt.err)
+		}
+	}
+}
+
+func BenchmarkParsing(b *testing.B) {
+	b.ReportAllocs()
+
+	name := mustNewName("foo.bar.example.com.")
+	msg := Message{
+		Header: Header{Response: true, Authoritative: true},
+		Questions: []Question{
+			{
+				Name:  name,
+				Type:  TypeA,
+				Class: ClassINET,
+			},
+		},
+		Answers: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Class: ClassINET,
+				},
+				&AResource{[4]byte{}},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Class: ClassINET,
+				},
+				&AAAAResource{[16]byte{}},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Class: ClassINET,
+				},
+				&CNAMEResource{name},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Class: ClassINET,
+				},
+				&NSResource{name},
+			},
+		},
+	}
+
+	buf, err := msg.Pack()
+	if err != nil {
+		b.Fatal("msg.Pack():", err)
+	}
+
+	for i := 0; i < b.N; i++ {
+		var p Parser
+		if _, err := p.Start(buf); err != nil {
+			b.Fatal("p.Start(buf):", err)
+		}
+
+		for {
+			_, err := p.Question()
+			if err == ErrSectionDone {
+				break
+			}
+			if err != nil {
+				b.Fatal("p.Question():", err)
+			}
+		}
+
+		for {
+			h, err := p.AnswerHeader()
+			if err == ErrSectionDone {
+				break
+			}
+			if err != nil {
+				panic(err)
+			}
+
+			switch h.Type {
+			case TypeA:
+				if _, err := p.AResource(); err != nil {
+					b.Fatal("p.AResource():", err)
+				}
+			case TypeAAAA:
+				if _, err := p.AAAAResource(); err != nil {
+					b.Fatal("p.AAAAResource():", err)
+				}
+			case TypeCNAME:
+				if _, err := p.CNAMEResource(); err != nil {
+					b.Fatal("p.CNAMEResource():", err)
+				}
+			case TypeNS:
+				if _, err := p.NSResource(); err != nil {
+					b.Fatal("p.NSResource():", err)
+				}
+			default:
+				b.Fatalf("unknown type: %T", h)
+			}
+		}
+	}
+}
+
+func BenchmarkBuilding(b *testing.B) {
+	b.ReportAllocs()
+
+	name := mustNewName("foo.bar.example.com.")
+	buf := make([]byte, 0, packStartingCap)
+
+	for i := 0; i < b.N; i++ {
+		var bld Builder
+		bld.StartWithoutCompression(buf, Header{Response: true, Authoritative: true})
+
+		if err := bld.StartQuestions(); err != nil {
+			b.Fatal("bld.StartQuestions():", err)
+		}
+		q := Question{
+			Name:  name,
+			Type:  TypeA,
+			Class: ClassINET,
+		}
+		if err := bld.Question(q); err != nil {
+			b.Fatalf("bld.Question(%+v): %v", q, err)
+		}
+
+		hdr := ResourceHeader{
+			Name:  name,
+			Class: ClassINET,
+		}
+		if err := bld.StartAnswers(); err != nil {
+			b.Fatal("bld.StartQuestions():", err)
+		}
+
+		ar := AResource{[4]byte{}}
+		if err := bld.AResource(hdr, ar); err != nil {
+			b.Fatalf("bld.AResource(%+v, %+v): %v", hdr, ar, err)
+		}
+
+		aaar := AAAAResource{[16]byte{}}
+		if err := bld.AAAAResource(hdr, aaar); err != nil {
+			b.Fatalf("bld.AAAAResource(%+v, %+v): %v", hdr, aaar, err)
+		}
+
+		cnr := CNAMEResource{name}
+		if err := bld.CNAMEResource(hdr, cnr); err != nil {
+			b.Fatalf("bld.CNAMEResource(%+v, %+v): %v", hdr, cnr, err)
+		}
+
+		nsr := NSResource{name}
+		if err := bld.NSResource(hdr, nsr); err != nil {
+			b.Fatalf("bld.NSResource(%+v, %+v): %v", hdr, nsr, err)
+		}
+
+		if _, err := bld.Finish(); err != nil {
+			b.Fatal("bld.Finish():", err)
+		}
+	}
+}
+
+func smallTestMsg() Message {
+	name := mustNewName("example.com.")
+	return Message{
+		Header: Header{Response: true, Authoritative: true},
+		Questions: []Question{
+			{
+				Name:  name,
+				Type:  TypeA,
+				Class: ClassINET,
+			},
+		},
+		Answers: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeA,
+					Class: ClassINET,
+				},
+				&AResource{[4]byte{127, 0, 0, 1}},
+			},
+		},
+		Authorities: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeA,
+					Class: ClassINET,
+				},
+				&AResource{[4]byte{127, 0, 0, 1}},
+			},
+		},
+		Additionals: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeA,
+					Class: ClassINET,
+				},
+				&AResource{[4]byte{127, 0, 0, 1}},
+			},
+		},
+	}
+}
+
+func largeTestMsg() Message {
+	name := mustNewName("foo.bar.example.com.")
+	return Message{
+		Header: Header{Response: true, Authoritative: true},
+		Questions: []Question{
+			{
+				Name:  name,
+				Type:  TypeA,
+				Class: ClassINET,
+			},
+		},
+		Answers: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeA,
+					Class: ClassINET,
+				},
+				&AResource{[4]byte{127, 0, 0, 1}},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeA,
+					Class: ClassINET,
+				},
+				&AResource{[4]byte{127, 0, 0, 2}},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeAAAA,
+					Class: ClassINET,
+				},
+				&AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeCNAME,
+					Class: ClassINET,
+				},
+				&CNAMEResource{mustNewName("alias.example.com.")},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeSOA,
+					Class: ClassINET,
+				},
+				&SOAResource{
+					NS:      mustNewName("ns1.example.com."),
+					MBox:    mustNewName("mb.example.com."),
+					Serial:  1,
+					Refresh: 2,
+					Retry:   3,
+					Expire:  4,
+					MinTTL:  5,
+				},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypePTR,
+					Class: ClassINET,
+				},
+				&PTRResource{mustNewName("ptr.example.com.")},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeMX,
+					Class: ClassINET,
+				},
+				&MXResource{
+					7,
+					mustNewName("mx.example.com."),
+				},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeSRV,
+					Class: ClassINET,
+				},
+				&SRVResource{
+					8,
+					9,
+					11,
+					mustNewName("srv.example.com."),
+				},
+			},
+		},
+		Authorities: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeNS,
+					Class: ClassINET,
+				},
+				&NSResource{mustNewName("ns1.example.com.")},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeNS,
+					Class: ClassINET,
+				},
+				&NSResource{mustNewName("ns2.example.com.")},
+			},
+		},
+		Additionals: []Resource{
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeTXT,
+					Class: ClassINET,
+				},
+				&TXTResource{"So Long, and Thanks for All the Fish"},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeTXT,
+					Class: ClassINET,
+				},
+				&TXTResource{"Hamster Huey and the Gooey Kablooie"},
+			},
+		},
+	}
+}
+
+const loremIpsum = `
+Lorem ipsum dolor sit amet, nec enim antiopam id, an ullum choro
+nonumes qui, pro eu debet honestatis mediocritatem. No alia enim eos,
+magna signiferumque ex vis. Mei no aperiri dissentias, cu vel quas
+regione. Malorum quaeque vim ut, eum cu semper aliquid invidunt, ei
+nam ipsum assentior.
+
+Nostrum appellantur usu no, vis ex probatus adipiscing. Cu usu illum
+facilis eleifend. Iusto conceptam complectitur vim id. Tale omnesque
+no usu, ei oblique sadipscing vim. At nullam voluptua usu, mei laudem
+reformidans et. Qui ei eros porro reformidans, ius suas veritus
+torquatos ex. Mea te facer alterum consequat.
+
+Soleat torquatos democritum sed et, no mea congue appareat, facer
+aliquam nec in. Has te ipsum tritani. At justo dicta option nec, movet
+phaedrum ad nam. Ea detracto verterem liberavisse has, delectus
+suscipiantur in mei. Ex nam meliore complectitur. Ut nam omnis
+honestatis quaerendum, ea mea nihil affert detracto, ad vix rebum
+mollis.
+
+Ut epicurei praesent neglegentur pri, prima fuisset intellegebat ad
+vim. An habemus comprehensam usu, at enim dignissim pro. Eam reque
+vivendum adipisci ea. Vel ne odio choro minimum. Sea admodum
+dissentiet ex. Mundi tamquam evertitur ius cu. Homero postea iisque ut
+pro, vel ne saepe senserit consetetur.
+
+Nulla utamur facilisis ius ea, in viderer diceret pertinax eum. Mei no
+enim quodsi facilisi, ex sed aeterno appareat mediocritatem, eum
+sententiae deterruisset ut. At suas timeam euismod cum, offendit
+appareat interpretaris ne vix. Vel ea civibus albucius, ex vim quidam
+accusata intellegebat, noluisse instructior sea id. Nec te nonumes
+habemus appellantur, quis dignissim vituperata eu nam.
+
+At vix apeirian patrioque vituperatoribus, an usu agam assum. Debet
+iisque an mea. Per eu dicant ponderum accommodare. Pri alienum
+placerat senserit an, ne eum ferri abhorreant vituperatoribus. Ut mea
+eligendi disputationi. Ius no tation everti impedit, ei magna quidam
+mediocritatem pri.
+
+Legendos perpetua iracundia ne usu, no ius ullum epicurei intellegam,
+ad modus epicuri lucilius eam. In unum quaerendum usu. Ne diam paulo
+has, ea veri virtute sed. Alia honestatis conclusionemque mea eu, ut
+iudico albucius his.
+
+Usu essent probatus eu, sed omnis dolor delicatissimi ex. No qui augue
+dissentias dissentiet. Laudem recteque no usu, vel an velit noluisse,
+an sed utinam eirmod appetere. Ne mea fuisset inimicus ocurreret. At
+vis dicant abhorreant, utinam forensibus nec ne, mei te docendi
+consequat. Brute inermis persecuti cum id. Ut ipsum munere propriae
+usu, dicit graeco disputando id has.
+
+Eros dolore quaerendum nam ei. Timeam ornatus inciderint pro id. Nec
+torquatos sadipscing ei, ancillae molestie per in. Malis principes duo
+ea, usu liber postulant ei.
+
+Graece timeam voluptatibus eu eam. Alia probatus quo no, ea scripta
+feugiat duo. Congue option meliore ex qui, noster invenire appellantur
+ea vel. Eu exerci legendos vel. Consetetur repudiandae vim ut. Vix an
+probo minimum, et nam illud falli tempor.
+
+Cum dico signiferumque eu. Sed ut regione maiorum, id veritus insolens
+tacimates vix. Eu mel sint tamquam lucilius, duo no oporteat
+tacimates. Atqui augue concludaturque vix ei, id mel utroque menandri.
+
+Ad oratio blandit aliquando pro. Vis et dolorum rationibus
+philosophia, ad cum nulla molestie. Hinc fuisset adversarium eum et,
+ne qui nisl verear saperet, vel te quaestio forensibus. Per odio
+option delenit an. Alii placerat has no, in pri nihil platonem
+cotidieque. Est ut elit copiosae scaevola, debet tollit maluisset sea
+an.
+
+Te sea hinc debet pericula, liber ridens fabulas cu sed, quem mutat
+accusam mea et. Elitr labitur albucius et pri, an labore feugait mel.
+Velit zril melius usu ea. Ad stet putent interpretaris qui. Mel no
+error volumus scripserit. In pro paulo iudico, quo ei dolorem
+verterem, affert fabellas dissentiet ea vix.
+
+Vis quot deserunt te. Error aliquid detraxit eu usu, vis alia eruditi
+salutatus cu. Est nostrud bonorum an, ei usu alii salutatus. Vel at
+nisl primis, eum ex aperiri noluisse reformidans. Ad veri velit
+utroque vis, ex equidem detraxit temporibus has.
+
+Inermis appareat usu ne. Eros placerat periculis mea ad, in dictas
+pericula pro. Errem postulant at usu, ea nec amet ornatus mentitum. Ad
+mazim graeco eum, vel ex percipit volutpat iudicabit, sit ne delicata
+interesset. Mel sapientem prodesset abhorreant et, oblique suscipit
+eam id.
+
+An maluisset disputando mea, vidit mnesarchum pri et. Malis insolens
+inciderint no sea. Ea persius maluisset vix, ne vim appellantur
+instructior, consul quidam definiebas pri id. Cum integre feugiat
+pericula in, ex sed persius similique, mel ne natum dicit percipitur.
+
+Primis discere ne pri, errem putent definitionem at vis. Ei mel dolore
+neglegentur, mei tincidunt percipitur ei. Pro ad simul integre
+rationibus. Eu vel alii honestatis definitiones, mea no nonumy
+reprehendunt.
+
+Dicta appareat legendos est cu. Eu vel congue dicunt omittam, no vix
+adhuc minimum constituam, quot noluisse id mel. Eu quot sale mutat
+duo, ex nisl munere invenire duo. Ne nec ullum utamur. Pro alterum
+debitis nostrum no, ut vel aliquid vivendo.
+
+Aliquip fierent praesent quo ne, id sit audiam recusabo delicatissimi.
+Usu postulant incorrupte cu. At pro dicit tibique intellegam, cibo
+dolore impedit id eam, et aeque feugait assentior has. Quando sensibus
+nec ex. Possit sensibus pri ad, unum mutat periculis cu vix.
+
+Mundi tibique vix te, duo simul partiendo qualisque id, est at vidit
+sonet tempor. No per solet aeterno deseruisse. Petentium salutandi
+definiebas pri cu. Munere vivendum est in. Ei justo congue eligendi
+vis, modus offendit omittantur te mel.
+
+Integre voluptaria in qui, sit habemus tractatos constituam no. Utinam
+melius conceptam est ne, quo in minimum apeirian delicata, ut ius
+porro recusabo. Dicant expetenda vix no, ludus scripserit sed ex, eu
+his modo nostro. Ut etiam sonet his, quodsi inciderint philosophia te
+per. Nullam lobortis eu cum, vix an sonet efficiendi repudiandae. Vis
+ad idque fabellas intellegebat.
+
+Eum commodo senserit conclusionemque ex. Sed forensibus sadipscing ut,
+mei in facer delicata periculis, sea ne hinc putent cetero. Nec ne
+alia corpora invenire, alia prima soleat te cum. Eleifend posidonium
+nam at.
+
+Dolorum indoctum cu quo, ex dolor legendos recteque eam, cu pri zril
+discere. Nec civibus officiis dissentiunt ex, est te liber ludus
+elaboraret. Cum ea fabellas invenire. Ex vim nostrud eripuit
+comprehensam, nam te inermis delectus, saepe inermis senserit.
+`

Some files were not shown because too many files changed in this diff